--- a/kerneltest/e32test/dmav2/d_dma2.cpp Tue May 11 17:28:22 2010 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1351 +0,0 @@
-// 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 "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:
-// Test driver for DMA V2 framework
-//
-//
-
-#include <kernel/kern_priv.h>
-#include <drivers/dma.h>
-#include "d_dma2.h"
-
-_LIT(KClientPanicCat, "D_DMA2");
-_LIT(KDFCThreadName,"D_DMA_DFC_THREAD");
-_LIT(KIsrCbDfcThreadName,"D_DMA_IsrCb_thread");
-const TInt KDFCThreadPriority=26;
-
-class TStopwatch
- {
-public:
- TStopwatch()
- :iStart(0), iStop(0)
- {}
-
- void Start()
- {iStart = NKern::FastCounter();}
-
- void Stop()
- {
- iStop = NKern::FastCounter();
-
- __KTRACE_OPT(KDMA, Kern::Printf(">TStopwatch::Stop FastCounter ticks: iStart=0x%lx iStop=0x%lx", iStart, iStop));
- }
-
- TUint64 ReadMicroSecs() const
- {
-#ifndef __SMP__
- TUint64 diff = 0;
- if(iStart > iStop)
- {
- diff = (KMaxTUint64 - iStart) + iStop;
- }
- else
- {
- diff = iStop - iStart;
- }
- return FastCountToMicroSecs(diff);
-#else
- //TODO On SMP it is possible for the value returned from
- //NKern::FastCounter to depend on the current CPU (ie.
- //NaviEngine)
- //
- //One solution would be to tie DFC's and ISR's to the same
- //core as the client, but this would reduce the usefulness of
- //SMP testing.
- return 0;
-#endif
- }
-private:
-
- TUint64 FastCountToMicroSecs(TUint64 aCount) const
- {
- const TUint64 countsPerS = NKern::FastCounterFrequency();
-
- TUint64 timeuS = (aCount*1000000)/countsPerS;
- __KTRACE_OPT(KDMA, Kern::Printf(">TStopwatch::FastCountToMicroSecs FastCounter ticks: aCount=0x%lx countsPerS=0x%lx time=0x%lx", aCount, countsPerS, timeuS));
- return timeuS;
- }
-
- TUint64 iStart;
- TUint64 iStop;
- };
-
-//////////////////////////////////////////////////////////////////////////////
-
-class DClientDmaRequest;
-/**
-Driver channel. Only accessible by a single client thread
-*/
-class DDmaTestSession : public DLogicalChannelBase
- {
-public:
- DDmaTestSession();
- virtual ~DDmaTestSession();
-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 DoGetInfo(TAny* aInfo);
-
- TInt OpenDmaChannel(TUint aPslCookie, TUint& aDriverCookie);
- TInt CloseDmaChannelByCookie(TUint aDriverCookie);
- TInt PauseDmaChannelByCookie(TUint aDriverCookie);
- TInt ResumeDmaChannelByCookie(TUint aDriverCookie);
- TInt GetChannelCapsByCookie(TUint aDriverCookie, SDmacCaps& aChannelCaps);
- TInt GetChannelCapsByCookie(TUint aDriverCookie, TDmacTestCaps& aChannelCaps);
- TInt CancelAllByCookie(TUint aDriverCookie);
- TInt IsrRedoRequestByCookie(TUint aDriverCookie,TUint32 aSrcAddr,TUint32 aDstAddr,TInt aTransferCount,TUint32 aPslRequestInfo,TBool aIsrCb);
- TInt IsQueueEmptyByCookie(TUint aDriverCookie, TBool& aQueueEmpty);
- TInt ChannelIsOpenedByCookie(TUint aDriverCookie, TBool& aChannelOpen);
- void CloseDmaChannelByIndex(TInt aIndex);
- void CancelAllByIndex(TInt aIndex);
- TInt PauseDmaChannelByIndex(TInt aIndex);
- TInt ResumeDmaChannelByIndex(TInt aIndex);
- TInt IsrRedoRequestByIndex(TInt aIndex,TUint32 aSrcAddr,TUint32 aDstAddr,TInt aTransferCount,TUint32 aPslRequestInfo,TBool aIsrCb);
- TInt CreateSharedChunk();
- TUint OpenSharedChunkHandle();
-
- /**
- Creates a new kernel-side DMA request object, associated with a previously
- opened channel
-
- @param aChannelCookie - A channel cookie as returned by OpenDmaChannel
- @param aRequestCookie - On success will be a cookie by which the dma request can be referred to
- @param aNewCallback - If true, then a new style DMA callback will be used
- */
- TInt CreateDmaRequest(TUint aChannelCookie, TUint& aRequestCookie, TBool aNewCallback = EFalse, TInt aMaxFragmentSizeBytes=0);
-
- //TODO what happens if a client closes a channel that
- //it still has dma requests associated with?
-
- /**
- Destroys a previously created dma request object
- */
- TInt DestroyDmaRequestByCookie(TUint aRequestCookie);
-
- void DestroyDmaRequestByIndex(TInt aIndex);
-
-
- TInt CookieToChannelIndex(TUint aDriverCookie) const;
- TInt CookieToRequestIndex(TUint aRequestCookie) const;
-
- void FixupTransferArgs(TDmaTransferArgs& aTransferArgs) const;
- TInt FragmentRequest(TUint aRequestCookie, const TDmaTransferArgs& aTransferArgs, TBool aLegacy=ETrue);
-
- TInt QueueRequest(TUint aRequestCookie, TRequestStatus* aStatus, TCallbackRecord* aRecord, TUint64* aDurationMicroSecs);
- DClientDmaRequest* RequestFromCookie(TUint aRequestCookie) const;
- TInt RequestFragmentCount(TUint aRequestCookie);
-
- TDmaV2TestInfo ConvertTestInfo(const TDmaTestInfo& aOldInfo) const;
-private:
- DThread* iClient;
- TDynamicDfcQue* iDfcQ;
- TDynamicDfcQue* iIsrCallbackDfcQ; // Will be used by requests which complete with an ISR callback
- static const TInt KMaxChunkSize = 8 * KMega;
- TLinAddr iChunkBase;
- DChunk* iChunk;
-
- RPointerArray<TDmaChannel> iChannels;
- RPointerArray<DClientDmaRequest> iClientDmaReqs;
- };
-
-
-/**
-Allows a TClientRequest to be associated with a DDmaRequest
-*/
-class DClientDmaRequest : public DDmaRequest
- {
-public:
- static DClientDmaRequest* Construct(DThread* aClient, TDfcQue* const aDfcQ, TDmaChannel& aChannel, TBool aNewStyle=EFalse, TInt aMaxTransferSize=0);
- ~DClientDmaRequest();
-
- TInt Queue(TRequestStatus* aRequestStatus, TCallbackRecord* aRecord, TUint64* aDurationMicroSecs);
- void AddRequeArgs(const TIsrRequeArgsSet& aRequeArgSet);
-
- TUint64 GetDuration()
- {return iStopwatch.ReadMicroSecs();}
-
-protected:
- TInt Create();
- /** Construct with old style callback */
- DClientDmaRequest(DThread* aClient, TDfcQue* const aDfcQ, TDmaChannel& aChannel, TInt aMaxTransferSize);
-
- /** Construct with new style callback */
- DClientDmaRequest(DThread* aClient, TDfcQue* const aDfcQ, TDmaChannel& aChannel, TBool aNewStyle, TInt aMaxTransferSize);
-
-private:
- static void CallbackOldStyle(TResult aResult, TAny* aRequest);
- static void Callback(TUint, TDmaResult, TAny*, SDmaDesHdr*);
- static void CompleteCallback(TAny* aRequest);
-
- void DoCallback(TUint, TDmaResult);
- TBool RedoRequest();
-
- //!< Used to return a TCallbackRecord and transfer time
- TClientDataRequest2<TCallbackRecord, TUint64>* iClientDataRequest;
-
- DThread* const iClient;
- TDfcQue* const iDfcQ; //!< Use the DDmaTestSession's dfc queue
- TDfc iDfc;
-
- TStopwatch iStopwatch;
- TIsrRequeArgsSet iIsrRequeArgSet;
- };
-
-DClientDmaRequest* DClientDmaRequest::Construct(DThread* aClient, TDfcQue* const aDfcQ, TDmaChannel& aChannel, TBool aNewStyle, TInt aMaxTransferSize)
- {
- DClientDmaRequest* dmaRequest = NULL;
- if(aNewStyle)
- {
-#ifdef DMA_APIV2
- dmaRequest = new DClientDmaRequest(aClient, aDfcQ, aChannel, aNewStyle, aMaxTransferSize);
-#else
- TEST_FAULT; // if a new style dma request was requested it should have been caught earlier
-#endif
- }
- else
- {
- dmaRequest = new DClientDmaRequest(aClient, aDfcQ, aChannel, aMaxTransferSize);
- }
-
- if(dmaRequest == NULL)
- {
- return dmaRequest;
- }
-
- const TInt r = dmaRequest->Create();
- if(r != KErrNone)
- {
- delete dmaRequest;
- dmaRequest = NULL;
- }
- return dmaRequest;
- }
-
-DClientDmaRequest::DClientDmaRequest(DThread* aClient, TDfcQue* const aDfcQ, TDmaChannel& aChannel, TInt aMaxFragmentSize)
- :DDmaRequest(aChannel, &CallbackOldStyle, this, aMaxFragmentSize),
- iClientDataRequest(NULL),
- iClient(aClient),
- iDfcQ(aDfcQ),
- iDfc(CompleteCallback,NULL, iDfcQ, KMaxDfcPriority)
- {
- }
-#ifdef DMA_APIV2
-DClientDmaRequest::DClientDmaRequest(DThread* aClient, TDfcQue* const aDfcQ, TDmaChannel& aChannel, TBool /*aNewStyle*/, TInt aMaxFragmentSize)
- :DDmaRequest(aChannel, &Callback, this, aMaxFragmentSize),
- iClientDataRequest(NULL),
- iClient(aClient),
- iDfcQ(aDfcQ),
- iDfc(CompleteCallback,NULL, iDfcQ, KMaxDfcPriority)
- {
- }
-#endif
-
-TInt DClientDmaRequest::Create()
- {
- return Kern::CreateClientDataRequest2(iClientDataRequest);
- }
-
-DClientDmaRequest::~DClientDmaRequest()
- {
- __KTRACE_OPT(KDMA, Kern::Printf(">DClientDmaRequest::~DClientDmaRequest"));
- if(iClientDataRequest)
- {
- Kern::DestroyClientRequest(iClientDataRequest);
- }
- }
-
-/**
-Queue the DClientDmaRequest.
-
-@param aRequestStatus Pointer to the client's request status
-@param aRecord Pointer to the user's TCallbackRecord, may be null
-@return
- -KErrInUse The client request is in use
- -KErrNone success
-*/
-TInt DClientDmaRequest::Queue(TRequestStatus* aRequestStatus, TCallbackRecord* aRecord, TUint64* aDurationMicroSecs)
- {
- __NK_ASSERT_ALWAYS(aRecord);
- __NK_ASSERT_ALWAYS(aDurationMicroSecs);
-
- //erase results from last transfer
- iClientDataRequest->Data1().Reset();
- iClientDataRequest->SetDestPtr1(aRecord);
-
- iClientDataRequest->SetDestPtr2(aDurationMicroSecs);
-
-
- TInt r = iClientDataRequest->SetStatus(aRequestStatus);
- if(r != KErrNone)
- {
- return r;
- }
-
- iStopwatch.Start();
-#ifdef DMA_APIV2
- r = DDmaRequest::Queue();
-#else
- // old version of queue did not return an error code
- DDmaRequest::Queue();
- r = KErrNone;
-#endif
-
- return r;
- }
-
-void DClientDmaRequest::AddRequeArgs(const TIsrRequeArgsSet& aRequeArgSet)
- {
- iIsrRequeArgSet = aRequeArgSet;
- }
-
-/**
-If a transfer complete callback in ISR context s received this will be
-called to redo the request with the first entry in the array
-
-@return ETrue If the redo was successful - indicates that another callback is comming
-*/
-TBool DClientDmaRequest::RedoRequest()
- {
- TIsrRequeArgs args = iIsrRequeArgSet.GetArgs();
- const TInt r = args.Call(iChannel);
- TCallbackRecord& record = iClientDataRequest->Data1();
- record.IsrRedoResult(r);
- return (r == KErrNone);
- }
-
-
-/**
-Calls TDmaChannel::IsrRedoRequest on aChannel
-with this object's parameters
-*/
-TInt TIsrRequeArgs::Call(TDmaChannel& aChannel)
- {
-#ifdef DMA_APIV2
- return aChannel.IsrRedoRequest(iSrcAddr, iDstAddr, iTransferCount, iPslRequestInfo, iIsrCb);
-#else
- TEST_FAULT;
- return KErrNotSupported;
-#endif
- }
-
-/**
-Check that both source and destination of ISR reque args will
-lie within the range specified by aStart and aSize.
-
-@param aStart The linear base address of the region
-@param aSize The size of the region
-*/
-TBool TIsrRequeArgs::CheckRange(TLinAddr aStart, TUint aSize) const
- {
- TUint physStart = Epoc::LinearToPhysical(aStart);
- TEST_ASSERT(physStart != KPhysAddrInvalid);
-
- TAddrRange chunk(physStart, aSize);
- TBool sourceOk = (iSrcAddr == KPhysAddrInvalid) ? ETrue : chunk.Contains(SourceRange());
-
- TBool destOk = (iDstAddr == KPhysAddrInvalid) ? ETrue : chunk.Contains(DestRange());
-
- return sourceOk && destOk;
- }
-
-TBool TIsrRequeArgsSet::CheckRange(TLinAddr aAddr, TUint aSize) const
- {
- for(TInt i=0; i<iCount; i++)
- {
- if(!iRequeArgs[i].CheckRange(aAddr, aSize))
- return EFalse;
- }
- return ETrue;
- }
-
-/**
-Translate an old style dma callback to a new-style one
-*/
-void DClientDmaRequest::CallbackOldStyle(TResult aResult, TAny* aArg)
- {
- __KTRACE_OPT(KDMA, Kern::Printf(">DClientDmaRequest::CallBackOldStyle: TResult result=%d", aResult));
- TEST_ASSERT(aResult != EBadResult);
- //translate result code
- const TDmaResult result = (aResult == EOk) ? EDmaResultOK : EDmaResultError;
-
- //call the new-style callback
- Callback(EDmaCallbackRequestCompletion, result, aArg, NULL);
- }
-
-
-/**
-The new style callback called by the DMA framework
-may be called in either thread or ISR context
-*/
-void DClientDmaRequest::Callback(TUint aCallbackType, TDmaResult aResult, TAny* aArg, SDmaDesHdr* aHdr)
- {
- const TInt context = NKern::CurrentContext();
- __KTRACE_OPT(KDMA, Kern::Printf(">DClientDmaRequest::CallBack: TDmaResult result = %d, NKern::TContext context = %d", aResult, context));
-
- DClientDmaRequest& self = *reinterpret_cast<DClientDmaRequest*>(aArg);
- self.DoCallback(aCallbackType, aResult);
-
- // decide if callback is complete
- const TBool transferComplete = aCallbackType & EDmaCallbackRequestCompletion;
- if(!transferComplete)
- {
- return;
- }
-
- // If there are reque args then redo this request
- // another callback would then be expected.
- // Requests can only be re-queued in ISR context, but we
- // do not check that here as it is up to the client to get
- // it right - also, we want to test that the PIL catches this
- // error
- if(!self.iIsrRequeArgSet.IsEmpty())
- {
- // If redo call was succesful, return and wait for next call back
- if(self.RedoRequest())
- return;
- }
-
- switch(context)
- {
- case NKern::EThread:
- {
- CompleteCallback(aArg);
- break;
- }
- case NKern::EInterrupt:
- {
- self.iDfc.iPtr = aArg;
- self.iDfc.Add();
- break;
- }
- case NKern::EIDFC: //fall-through
- case NKern::EEscaped:
- default:
- TEST_FAULT;
- }
- }
-
-/**
-Log results of callback. May be called in either thread or ISR context
-*/
-void DClientDmaRequest::DoCallback(TUint aCallbackType, TDmaResult aResult)
- {
- iStopwatch.Stop(); //sucessive calls will simply over write the stop time
-
- // This will always be done whether the client requested a
- // callback record or not
- TCallbackRecord& record = iClientDataRequest->Data1();
- record.ProcessCallback(aCallbackType, aResult);
- }
-
-/**
-This function may either be called directly or queued as a DFC
-*/
-void DClientDmaRequest::CompleteCallback(TAny* aArg)
- {
- __KTRACE_OPT(KDMA, Kern::Printf(">DClientDmaRequest::CompleteCallBack thread %O", &Kern::CurrentThread()));
- __ASSERT_NOT_ISR;
-
- DClientDmaRequest& self = *reinterpret_cast<DClientDmaRequest*>(aArg);
-
- self.iClientDataRequest->Data2() = self.iStopwatch.ReadMicroSecs();
-
- //Assert that we called SetRequestStatus on this object before
- //queueing
- __NK_ASSERT_DEBUG(self.iClientDataRequest->IsReady());
-
- // This is an inelegant, temporary, solution to the following problem:
- //
- // If a dma request completes with an ISR callback the test
- // framework will queue this function as a DFC which
- // will then signal the user-side client. As a consequence of
- // this the user side client may then decide to destroy this
- // request. However, untill the DMA framework's DFC has run
- // and called OnDeque() on this request, it is still considered as
- // queued. Since it is possible that this DFC could run
- // before the DMA fw's DFC, this request could get destroyed while
- // it is stil queued, triggering a PIL assertion.
- //
- // The real fix is likely be for the PIL to call the callback
- // twice, but with different arguments, once to annonunce the
- // ISR and again to announce the dequeue.
- //
- // Here we poll and wait for this request to be dequeued. Note,
- // this DFC is currently run on a separate DFC queue, otherwise
- // it could get deadlocked. An alternative to polling would be
- // to use DCondVar, but that would require PIL modification
-
- if(NKern::CurrentThread() == self.iDfcQ->iThread)
- {
- // Only need to poll if we aren't on the channel's DFC queue
- for(;;)
- {
- // once the request has been unqueued it
- // can only be queued again by the client
- const TBool queued = __e32_atomic_load_acq32(&self.iQueued);
- if(!queued)
- break;
- __KTRACE_OPT(KDMA, Kern::Printf("Waiting for requeuest to be dequeued"));
- NKern::Sleep(10);
- }
- }
- else
- {
- // If we are on the channel's DFCQ we should be dequeued
- // already
- __NK_ASSERT_DEBUG(!__e32_atomic_load_acq32(&self.iQueued));
- }
-
- // We can always complete with KErrNone, the actual DMA result is
- // logged in the TCallbackRecord
- Kern::QueueRequestComplete(self.iClient, self.iClientDataRequest, KErrNone);
- }
-
-const TInt DDmaTestSession::KMaxChunkSize;
-
-TInt DDmaTestSession::RequestUserHandle(DThread* aThread, TOwnerType aType)
- {
- if (aType!=EOwnerThread || aThread!=iClient)
- return KErrAccessDenied;
- return KErrNone;
- }
-
-DDmaTestSession::DDmaTestSession()
- : iClient(NULL), iDfcQ(NULL), iIsrCallbackDfcQ(NULL), iChunkBase(0), iChunk(NULL)
- {}
-
-// called in thread critical section
-TInt DDmaTestSession::DoCreate(TInt /*aUnit*/, const TDesC8* aInfo, const TVersion& /*aVer*/)
- {
- __NK_ASSERT_ALWAYS(iDfcQ == NULL);
- __NK_ASSERT_ALWAYS(iIsrCallbackDfcQ == NULL);
-
- TInt r = Kern::DynamicDfcQCreate(iDfcQ, KDFCThreadPriority, KDFCThreadName);
- if (r != KErrNone)
- return r;
- NKern::ThreadSetCpuAffinity((NThread*)(iDfcQ->iThread), KCpuAffinityAny);
-
- r = Kern::DynamicDfcQCreate(iIsrCallbackDfcQ, KDFCThreadPriority, KIsrCbDfcThreadName);
- if (r != KErrNone)
- return r;
- NKern::ThreadSetCpuAffinity((NThread*)(iIsrCallbackDfcQ->iThread), KCpuAffinityAny);
-
- iClient = &Kern::CurrentThread();
-
- r = CreateSharedChunk();
- return r;
- }
-
-DDmaTestSession::~DDmaTestSession()
- {
- //Destroy requests before channels
- //or we will trigger an assertion
- while(iClientDmaReqs.Count())
- {
- DestroyDmaRequestByIndex(0);
- }
- iClientDmaReqs.Close();
-
- while(iChannels.Count())
- {
- CloseDmaChannelByIndex(0);
- }
- iChannels.Close();
-
-
- if (iDfcQ)
- {
- iDfcQ->Destroy();
- }
-
- if (iIsrCallbackDfcQ)
- {
- iIsrCallbackDfcQ->Destroy();
- }
-
- if(iChunk)
- {
- Kern::ChunkClose(iChunk);
- iChunk = NULL;
- }
- }
-
-TInt DDmaTestSession::Request(TInt aFunction, TAny* a1, TAny* a2)
- {
- __NK_ASSERT_DEBUG(&Kern::CurrentThread() == iClient);
-
- switch (aFunction)
- {
- case RDmaSession::EOpenChannel:
- {
- TUint pslCookie = (TUint)a1;
- TUint driverCookie = 0;
- TInt r = OpenDmaChannel(pslCookie, driverCookie);
- umemput32(a2, &driverCookie, sizeof(TAny*));
- return r;
- }
- case RDmaSession::ECloseChannel:
- {
- TUint driverCookie = reinterpret_cast<TUint>(a1);
- TInt r = CloseDmaChannelByCookie(driverCookie);
- return r;
- }
- case RDmaSession::EChannelCaps:
- {
- TUint driverCookie = reinterpret_cast<TUint>(a1);
- TPckgBuf<TDmacTestCaps> capsBuf;
- TInt r = GetChannelCapsByCookie(driverCookie, capsBuf());
- Kern::KUDesPut(*reinterpret_cast<TDes8*>(a2), capsBuf);
- return r;
- }
- case RDmaSession::EPauseChannel:
- {
- TUint driverCookie = reinterpret_cast<TUint>(a1);
- TInt r = PauseDmaChannelByCookie(driverCookie);
- return r;
- }
- case RDmaSession::EResumeChannel:
- {
- TUint driverCookie = reinterpret_cast<TUint>(a1);
- TInt r = ResumeDmaChannelByCookie(driverCookie);
- return r;
- }
- case RDmaSession::EFragmentCount:
- {
- TUint requestCookie = reinterpret_cast<TUint>(a1);
- TInt r = RequestFragmentCount(requestCookie);
- return r;
- }
- case RDmaSession::ERequestOpen:
- {
- RDmaSession::TRequestCreateArgs createArgs(0, EFalse, 0);
- TPckg<RDmaSession::TRequestCreateArgs> package(createArgs);
- Kern::KUDesGet(package, *reinterpret_cast<TDes8*>(a1));
-
- const TUint channelCookie = createArgs.iChannelCookie;
- TUint requestCookie = 0;
-
- TInt r = CreateDmaRequest(channelCookie, requestCookie, createArgs.iNewStyle, createArgs.iMaxFragmentSize);
-
- umemput32(a2, &requestCookie, sizeof(TAny*));
- return r;
- }
- case RDmaSession::ERequestClose:
- {
- const TUint requestCookie = reinterpret_cast<TUint>(a1);
- return DestroyDmaRequestByCookie(requestCookie);
- }
- case RDmaSession::EFragmentLegacy:
- case RDmaSession::EFragment:
- {
- TPckgBuf<RDmaSession::TFragmentArgs> argsBuff;
- Kern::KUDesGet(argsBuff, *reinterpret_cast<TDes8*>(a1));
- const TUint requestCookie = argsBuff().iRequestCookie;
-
- //must remove constness as we actually need to
- //convert the src and dst offsets to addresses
- TDmaTransferArgs& transferArgs = const_cast<TDmaTransferArgs&>(argsBuff().iTransferArgs);
-
- //convert address offsets in to kernel virtual addresses
- FixupTransferArgs(transferArgs);
-
- TEST_ASSERT((TAddressParms(transferArgs).CheckRange(iChunkBase, iChunk->Size())));
-
- TInt r = KErrGeneral;
-
- TStopwatch clock;
- clock.Start();
- switch (aFunction)
- {
- case RDmaSession::EFragmentLegacy:
- r = FragmentRequest(requestCookie, transferArgs, ETrue); break;
- case RDmaSession::EFragment:
- r = FragmentRequest(requestCookie, transferArgs, EFalse); break;
- default:
- TEST_FAULT;
- }
- clock.Stop();
-
- const TUint64 time = clock.ReadMicroSecs();
-
- TUint64* const timePtr = argsBuff().iDurationMicroSecs;
- if(timePtr)
- {
- umemput(timePtr, &time, sizeof(time));
- }
- return r;
- }
- case RDmaSession::EQueueRequest:
- {
- TPckgBuf<RDmaSession::TQueueArgs> argsBuff;
- Kern::KUDesGet(argsBuff, *reinterpret_cast<TDes8*>(a1));
-
- //this is an Asynchronous request
- const TUint requestCookie = argsBuff().iRequestCookie;
- TRequestStatus* requestStatus = argsBuff().iStatus;
- TCallbackRecord* callbackRec = argsBuff().iCallbackRecord;
- TUint64* duration = argsBuff().iDurationMicroSecs;
-
- TInt r = QueueRequest(requestCookie, requestStatus, callbackRec, duration);
- if(r != KErrNone)
- {
- Kern::RequestComplete(requestStatus, r);
- }
- return r;
- }
- case RDmaSession::EQueueRequestWithReque:
- {
- //TODO can common code with EQueueRequest be extracted?
- TPckgBuf<RDmaSession::TQueueArgsWithReque> argsBuff;
- Kern::KUDesGet(argsBuff, *reinterpret_cast<TDes8*>(a1));
-
- //this is an Asynchronous request
- const TUint requestCookie = argsBuff().iRequestCookie;
- TRequestStatus* requestStatus = argsBuff().iStatus;
- TCallbackRecord* callbackRec = argsBuff().iCallbackRecord;
- TUint64* duration = argsBuff().iDurationMicroSecs;
-
- TInt r = KErrNotFound;
-
- DClientDmaRequest* const request = RequestFromCookie(requestCookie);
- if(request != NULL)
- {
- argsBuff().iRequeSet.Fixup(iChunkBase);
- //TODO reque args must be substituted in order to
- //check the range. The original transfer args are not
- //available when queue is called, they could
- //however be stored within DClientDmaRequest
- //TEST_ASSERT((argsBuff().iRequeSet.CheckRange(iChunkBase, iChunk->Size())));
- request->AddRequeArgs(argsBuff().iRequeSet);
-
- r = QueueRequest(requestCookie, requestStatus, callbackRec, duration);
- }
-
- if(r != KErrNone)
- {
- Kern::RequestComplete(requestStatus, r);
- }
- return r;
- }
- case RDmaSession::EIsrRedoRequest:
- {
- TPckgBuf<RDmaSession::TIsrRedoReqArgs> argsBuff;
- Kern::KUDesGet(argsBuff, *reinterpret_cast<TDes8*>(a1));
-
- const TUint driverCookie = argsBuff().iDriverCookie;
- const TUint32 srcAddr = argsBuff().iSrcAddr;
- const TUint32 dstAddr = argsBuff().iDstAddr;
- const TInt transferCount = argsBuff().iTransferCount;
- const TUint32 pslRequestInfo = argsBuff().iPslRequestInfo;
- const TBool isrCb = argsBuff().iIsrCb;
-
- TInt r = IsrRedoRequestByCookie(driverCookie,srcAddr,dstAddr,transferCount,pslRequestInfo,isrCb);
- return r;
- }
- case RDmaSession::EIsOpened:
- {
- TUint driverCookie = (TUint)a1;
- TBool channelOpen = EFalse;;
- TInt r = ChannelIsOpenedByCookie(driverCookie,channelOpen);
- umemput32(a2, &channelOpen, sizeof(TAny*));
- return r;
- }
- case RDmaSession::EIsQueueEmpty:
- {
- TUint driverCookie = (TUint)a1;
- TBool queueEmpty = EFalse;;
- TInt r = IsQueueEmptyByCookie(driverCookie,queueEmpty);
- umemput32(a2, &queueEmpty, sizeof(TAny*));
- return r;
- }
- case RDmaSession::ECancelAllChannel:
- {
- TUint driverCookie = reinterpret_cast<TUint>(a1);
- TInt r = CancelAllByCookie(driverCookie);
- return r;
- }
- case RDmaSession::EOpenSharedChunk:
- {
- return OpenSharedChunkHandle();
- }
- case RDmaSession::EGetTestInfo:
- {
-#ifdef DMA_APIV2
- TPckgC<TDmaV2TestInfo> package(DmaTestInfoV2());
-#else
- TPckgC<TDmaV2TestInfo> package(ConvertTestInfo(DmaTestInfo()));
-#endif
- Kern::KUDesPut(*reinterpret_cast<TDes8*>(a1), package);
- return KErrNone;
- }
- default:
- Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
- return KErrGeneral;
- }
- }
-
-TInt DDmaTestSession::OpenDmaChannel(TUint aPslCookie, TUint& aDriverCookie )
- {
- TDmaChannel::SCreateInfo info;
- info.iCookie = aPslCookie;
- info.iDfcQ = iDfcQ;
- info.iDfcPriority = 3;
- info.iDesCount = 128;
-
- TDmaChannel* channel = NULL;
-
- //cs so thread can't be killed between
- //opening channel and adding to array
- NKern::ThreadEnterCS();
- TInt r = TDmaChannel::Open(info, channel);
- if(KErrNone == r)
- {
- __NK_ASSERT_ALWAYS(channel);
-
- __KTRACE_OPT(KDMA, Kern::Printf("OpenDmaChannel: channel@ 0x%08x", channel));
-
-
- TInt err = iChannels.Append(channel);
- if(KErrNone == err)
- {
- aDriverCookie = reinterpret_cast<TUint>(channel);
- }
- else
- {
- channel->Close();
- r = KErrNoMemory;
- }
- }
- NKern::ThreadLeaveCS();
-
- return r;
- }
-
-TInt DDmaTestSession::CookieToChannelIndex(TUint aDriverCookie) const
- {
- const TInt r = iChannels.Find(reinterpret_cast<TDmaChannel*>(aDriverCookie));
-
- if(r < 0)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("CookieToChannelIndex: cookie 0x%08x not found!", aDriverCookie));
- }
- return r;
- }
-
-TInt DDmaTestSession::CookieToRequestIndex(TUint aRequestCookie) const
- {
- const TInt r = iClientDmaReqs.Find(reinterpret_cast<DClientDmaRequest*>(aRequestCookie));
-
- if(r < 0)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("CookieToRequestIndex: cookie 0x%08x not found!", aRequestCookie));
- }
- return r;
- }
-
-void DDmaTestSession::CloseDmaChannelByIndex(TInt aIndex)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("CloseDmaChannelByIndex: %d", aIndex));
- __NK_ASSERT_DEBUG(aIndex < iChannels.Count());
- // cs so client thread can't be killed between removing channel from
- // array and closing it.
- NKern::ThreadEnterCS();
- TDmaChannel* channel = iChannels[aIndex];
- iChannels.Remove(aIndex);
- channel->Close();
- NKern::ThreadLeaveCS();
- }
-
-TInt DDmaTestSession::CloseDmaChannelByCookie(TUint aDriverCookie)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("CloseDmaChannelByCookie: 0x%08x", aDriverCookie));
- const TInt index = CookieToChannelIndex(aDriverCookie);
-
- if(index >= 0)
- {
- CloseDmaChannelByIndex(index);
- return KErrNone;
- }
- else
- {
- return KErrNotFound;
- }
- }
-
-TInt DDmaTestSession::CancelAllByCookie(TUint aDriverCookie)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("CancelAllByCookie: 0x%08x", aDriverCookie));
- const TInt index = CookieToChannelIndex(aDriverCookie);
-
- if(index >= 0)
- {
- CancelAllByIndex(index);
- return KErrNone;
- }
- else
- {
- return KErrNotFound;
- }
- }
-
-void DDmaTestSession::CancelAllByIndex(TInt aIndex)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("CancelAllByIndex: %d", aIndex));
- __NK_ASSERT_DEBUG(aIndex < iChannels.Count());
-
- TDmaChannel* channel = iChannels[aIndex];
- iChannels.Remove(aIndex);
- channel->CancelAll();
- }
-
-TInt DDmaTestSession::PauseDmaChannelByIndex(TInt aIndex)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("PauseDmaChannelByIndex: %d", aIndex));
- __NK_ASSERT_DEBUG(aIndex < iChannels.Count());
-
-#ifdef DMA_APIV2
- TDmaChannel* channel = iChannels[aIndex];
- return channel->Pause();
-#else
- return KErrNotSupported;
-#endif
- }
-
-TInt DDmaTestSession::PauseDmaChannelByCookie(TUint aDriverCookie)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("PauseDmaChannelByCookie: 0x%08x", aDriverCookie));
- const TInt index = CookieToChannelIndex(aDriverCookie);
-
- if(index >= 0)
- {
- TInt r = PauseDmaChannelByIndex(index);
- return r;
- }
- else
- {
- return KErrNotFound;
- }
- }
-
-TInt DDmaTestSession::ResumeDmaChannelByIndex(TInt aIndex)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("ResumeDmaChannelByIndex: %d", aIndex));
- __NK_ASSERT_DEBUG(aIndex < iChannels.Count());
-
-#ifdef DMA_APIV2
- TDmaChannel* channel = iChannels[aIndex];
- return channel->Resume();
-#else
- return KErrNotSupported;
-#endif
- }
-
-TInt DDmaTestSession::ResumeDmaChannelByCookie(TUint aDriverCookie)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("ResumeDmaChannelByCookie: 0x%08x", aDriverCookie));
- const TInt index = CookieToChannelIndex(aDriverCookie);
-
- if(index >= 0)
- {
- TInt r = ResumeDmaChannelByIndex(index);
- return r;
- }
- else
- {
- return KErrNotFound;
- }
- }
-
-TInt DDmaTestSession::IsrRedoRequestByCookie(TUint aDriverCookie,TUint32 aSrcAddr,TUint32 aDstAddr,TInt aTransferCount,TUint32 aPslRequestInfo,TBool aIsrCb)
-{
- __KTRACE_OPT(KDMA, Kern::Printf("IsrRedoRequestByCookie: 0x%08x", aDriverCookie));
- const TInt index = CookieToChannelIndex(aDriverCookie);
-
- if(index >= 0)
- {
- TInt r = IsrRedoRequestByIndex(index,aSrcAddr,aDstAddr,aTransferCount,aPslRequestInfo,aIsrCb);
- return r;
- }
- else
- {
- return KErrNotFound;
- }
-}
-
-TInt DDmaTestSession::IsrRedoRequestByIndex(TInt aIndex,TUint32 aSrcAddr,TUint32 aDstAddr,TInt aTransferCount,TUint32 aPslRequestInfo,TBool aIsrCb)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("IsrRedoRequestByIndex: %d", aIndex));
- __NK_ASSERT_DEBUG(aIndex < iChannels.Count());
-
-#ifdef DMA_APIV2
- TDmaChannel* channel = iChannels[aIndex];
- return channel->IsrRedoRequest(aSrcAddr,aDstAddr,aTransferCount,aPslRequestInfo,aIsrCb);
-#else
- return KErrNotSupported;
-#endif
- }
-
-/**
-aChannelCaps will be set to "NULL" values
-*/
-TInt DDmaTestSession::GetChannelCapsByCookie(TUint aDriverCookie, TDmacTestCaps& aChannelCaps)
- {
- SDmacCaps caps = {0,}; //initialise with NULL values
- TInt r = GetChannelCapsByCookie(aDriverCookie, caps);
-
- if(r == KErrNotSupported)
- {
- //If we can not query caps it means
- //that we are using the v1 driver
- //we construct a empty TDmacTestCaps
- //but with an iPILVersion of 1
- const TDmacTestCaps nullCapsV1(caps, 1);
- aChannelCaps = nullCapsV1;
- r = KErrNone;
- }
- else if(r == KErrNone)
- {
- const TDmacTestCaps capsV2(caps, 2);
- aChannelCaps = capsV2;
- }
-
- return r;
- }
-
-/**
-Will return the capabilities of the DMA channel.
-Querying SDmacCaps is not possible on V1 of the DMA framework.
-In that case an error of KErrNotSupported will be returned
-*/
-TInt DDmaTestSession::GetChannelCapsByCookie(TUint aDriverCookie, SDmacCaps& aChannelCaps)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("GetChannelCapsByCookie: 0x%08x", aDriverCookie));
- const TInt index = CookieToChannelIndex(aDriverCookie);
- if(index >= 0)
- {
-#ifdef DMA_APIV2
- aChannelCaps = iChannels[index]->DmacCaps();
- return KErrNone;
-#else
- return KErrNotSupported;
-#endif
- }
- else
- {
- return KErrNotFound;
- }
- }
-
-TInt DDmaTestSession::IsQueueEmptyByCookie(TUint aDriverCookie, TBool& aQueueEmpty)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("IsQueueEmptyByCookie: 0x%08x", aDriverCookie));
- const TInt index = CookieToChannelIndex(aDriverCookie);
-
- if(index >= 0)
- {
- aQueueEmpty=iChannels[index]->IsQueueEmpty();
- return KErrNone;
- }
- else
- {
- return KErrNotFound;
- }
- }
-
-TInt DDmaTestSession::ChannelIsOpenedByCookie(TUint aDriverCookie, TBool& aChannelOpen)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("ChannelIsOpenedByCookie: 0x%08x", aDriverCookie));
- const TInt index = CookieToChannelIndex(aDriverCookie);
-
- if(index >= 0)
- {
- aChannelOpen=iChannels[index]->IsOpened();
- return KErrNone;
- }
- else
- {
- return KErrNotFound;
- }
- }
-
-TInt DDmaTestSession::CreateDmaRequest(TUint aChannelCookie, TUint& aRequestCookie, TBool aNewCallback, TInt aMaxFragmentSizeBytes)
- {
-#ifndef DMA_APIV2
- if(aNewCallback)
- return KErrNotSupported;
-#endif
-
- TInt channelIndex = CookieToChannelIndex(aChannelCookie);
- if(channelIndex < 0)
- return channelIndex;
-
- NKern::ThreadEnterCS();
- DClientDmaRequest* request = DClientDmaRequest::Construct(iClient, iIsrCallbackDfcQ, *iChannels[channelIndex], aNewCallback, aMaxFragmentSizeBytes);
- if(request == NULL)
- {
- NKern::ThreadLeaveCS();
- return KErrNoMemory;
- }
-
- TInt r = iClientDmaReqs.Append(request);
- if(r == KErrNone)
- {
- aRequestCookie = reinterpret_cast<TUint>(request);
- }
- else
- {
- delete request;
- }
- NKern::ThreadLeaveCS();
-
- return r;
- }
-
-TInt DDmaTestSession::DestroyDmaRequestByCookie(TUint aRequestCookie)
- {
- TInt requestIndex = CookieToRequestIndex(aRequestCookie);
- if(requestIndex < 0)
- return requestIndex;
-
- DestroyDmaRequestByIndex(requestIndex);
-
- return KErrNone;
- }
-
-void DDmaTestSession::DestroyDmaRequestByIndex(TInt aIndex)
- {
- __KTRACE_OPT(KDMA, Kern::Printf("DestroyDmaRequestByIndex: %d", aIndex));
- __NK_ASSERT_DEBUG(aIndex < iClientDmaReqs.Count());
- NKern::ThreadEnterCS();
-
- DClientDmaRequest* request = iClientDmaReqs[aIndex];
- iClientDmaReqs.Remove(aIndex);
- delete request;
-
- NKern::ThreadLeaveCS();
- }
-
-TInt DDmaTestSession::CreateSharedChunk()
- {
- // Enter critical section so we can't die and leak the objects we are creating
- // I.e. the TChunkCleanup and DChunk (Shared Chunk)
- NKern::ThreadEnterCS();
-
- // Create the chunk
- TChunkCreateInfo info;
- info.iType = TChunkCreateInfo::ESharedKernelSingle;
- info.iMaxSize = KMaxChunkSize;
- info.iMapAttr = EMapAttrFullyBlocking | EMapAttrUserRw;
- info.iOwnsMemory = ETrue;
- info.iDestroyedDfc = NULL;
-
- DChunk* chunk;
- TUint32 mapAttr;
- TInt r = Kern::ChunkCreate(info, chunk, iChunkBase, mapAttr);
- if(r!=KErrNone)
- {
- NKern::ThreadLeaveCS();
- return r;
- }
-
- // Map our device's memory into the chunk (at offset 0)
- TUint32 physicalAddr;
- r = Kern::ChunkCommitContiguous(chunk,0,KMaxChunkSize, physicalAddr);
- if(r!=KErrNone)
- {
- // Commit failed so tidy-up...
- Kern::ChunkClose(chunk);
- }
- else
- {
- iChunk = chunk;
- }
-
- // Can leave critical section now that we have saved pointers to created objects
- NKern::ThreadLeaveCS();
-
- return r;
- }
-
-TUint DDmaTestSession::OpenSharedChunkHandle()
- {
- NKern::ThreadEnterCS();
- const TInt r = Kern::MakeHandleAndOpen(NULL, iChunk);
- NKern::ThreadLeaveCS();
- return r;
- }
-
-void DDmaTestSession::FixupTransferArgs(TDmaTransferArgs& aTransferArgs) const
- {
- aTransferArgs.iSrcConfig.iAddr += iChunkBase;
- aTransferArgs.iDstConfig.iAddr += iChunkBase;
- }
-
-#ifndef DMA_APIV2
-static TInt FragmentCount(DDmaRequest* aRequest)
- {
- TInt count = 0;
- for (SDmaDesHdr* pH = aRequest->iFirstHdr; pH != NULL; pH = pH->iNext)
- count++;
- return count;
- }
-#endif
-
-TInt DDmaTestSession::RequestFragmentCount(TUint aRequestCookie)
- {
- TInt requestIndex = CookieToRequestIndex(aRequestCookie);
- if(requestIndex < 0)
- return requestIndex;
-#ifdef DMA_APIV2
- TInt r = iClientDmaReqs[requestIndex]->FragmentCount();
-#else
- TInt r = FragmentCount(iClientDmaReqs[requestIndex]);
-#endif
-
- return r;
- }
-
-TInt DDmaTestSession::FragmentRequest(TUint aRequestCookie, const TDmaTransferArgs& aTransferArgs, TBool aLegacy)
- {
- __KTRACE_OPT(KDMA, Kern::Printf(">FragmentRequest: cookie=0x%08x, legacy=%d", aRequestCookie, aLegacy));
- TInt requestIndex = CookieToRequestIndex(aRequestCookie);
- if(requestIndex < 0)
- return requestIndex;
-
- TInt r = KErrNotSupported;
- if(aLegacy)
- {
- // TODO we can extract the required info from the struct to
- // set flags
- TUint flags = KDmaMemSrc | KDmaIncSrc | KDmaMemDest | KDmaIncDest;
-
- const TUint src = aTransferArgs.iSrcConfig.iAddr;
- const TUint dst = aTransferArgs.iDstConfig.iAddr;
- r = iClientDmaReqs[requestIndex]->Fragment(src, dst, aTransferArgs.iTransferCount, flags, NULL);
- }
- else
- {
-#ifdef DMA_APIV2
- r = iClientDmaReqs[requestIndex]->Fragment(aTransferArgs);
-#else
- r = KErrNotSupported;
-#endif
- }
- return r;
- }
-
-/**
-Queue the request refered to by aRequestCookie
-
-@param aRequestCookie Client identifier for the DDmaRequest
-@param aStatus Pointer to the client's TRequestStatus
-@param aRecord Pointer to the client's TCallbackRecord
-@return
- - KErrNotFound - aRequestCookie was invalid
- - KErrNone - Success
-*/
-TInt DDmaTestSession::QueueRequest(TUint aRequestCookie, TRequestStatus* aStatus, TCallbackRecord* aRecord, TUint64* aDurationMicroSecs)
- {
- __KTRACE_OPT(KDMA, Kern::Printf(">QueueRequest: 0x%08x", aRequestCookie));
-
- DClientDmaRequest* request = RequestFromCookie(aRequestCookie);
- if(request == NULL)
- return KErrNotFound;
-
- return request->Queue(aStatus, aRecord, aDurationMicroSecs);
- }
-
-DClientDmaRequest* DDmaTestSession::RequestFromCookie(TUint aRequestCookie) const
- {
- TInt requestIndex = CookieToRequestIndex(aRequestCookie);
- if(requestIndex < 0)
- return NULL;
-
- return (iClientDmaReqs[requestIndex]);
- }
-
-TDmaV2TestInfo DDmaTestSession::ConvertTestInfo(const TDmaTestInfo& aOldInfo) const
- {
- TDmaV2TestInfo newInfo;
- newInfo.iMaxTransferSize = aOldInfo.iMaxTransferSize;
- newInfo.iMemAlignMask = aOldInfo.iMemAlignMask;
- newInfo.iMemMemPslInfo = aOldInfo.iMemMemPslInfo;
-
- newInfo.iMaxSbChannels = aOldInfo.iMaxSbChannels;
- for(TInt i=0; i<aOldInfo.iMaxSbChannels; i++)
- newInfo.iSbChannels[i] = aOldInfo.iSbChannels[i];
-
- newInfo.iMaxDbChannels = aOldInfo.iMaxDbChannels;
- for(TInt i=0; i<aOldInfo.iMaxDbChannels; i++)
- newInfo.iDbChannels[i] = aOldInfo.iDbChannels[i];
-
- newInfo.iMaxSgChannels = aOldInfo.iMaxSgChannels;
- for(TInt i=0; i<aOldInfo.iMaxSgChannels; i++)
- newInfo.iSgChannels[i] = aOldInfo.iSgChannels[i];
-
- //TODO will want to add initialisation for Asym channels
- //when these are available
-
- return newInfo;
- }
-//////////////////////////////////////////////////////////////////////////////
-
-class DDmaTestFactory : public DLogicalDevice
- {
-public:
- DDmaTestFactory();
- // from DLogicalDevice
- virtual ~DDmaTestFactory()
- {
- __KTRACE_OPT(KDMA, Kern::Printf(">DDmaTestFactory::~DDmaTestFactory"));
- }
- 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 DDmaTestSession;
- return aChannel ? KErrNone : KErrNoMemory;
- }
-
-
-TInt DDmaTestFactory::Install()
- {
- return SetName(&KTestDmaLddName);
- }
-
-
-void DDmaTestFactory::GetCaps(TDes8& /*aDes*/) const
- {
- }
-
-//////////////////////////////////////////////////////////////////////////////
-
-DECLARE_STANDARD_LDD()
- {
- return new DDmaTestFactory;
- }