diff -r a5496987b1da -r 189ece41fa29 kerneltest/e32test/dmav2/dma2_sim.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/dmav2/dma2_sim.cpp Fri Jul 09 13:13:20 2010 +0100 @@ -0,0 +1,728 @@ +// Copyright (c) 2010 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: +// os/kernelhwsrv/kerneltest/e32test/dmav2/dma2_sim.cpp +// Partial simulation of DMA2 PSL +// +// + + +#include + +#include +#include + +#include "d_dma2.h" + +// Debug support +static const char KDmaPanicCat[] = "DMA PSL - " __FILE__; + +static const TInt KMaxTransferLen = 0x1000; // max transfer length for this DMAC +static const TInt KMemAlignMask = 0; // memory addresses passed to DMAC must be multiple of 8 +static const TInt KDesCount = 160; // Initial DMA descriptor count + +class TDmaDesc +// +// Hardware DMA descriptor +// + { +public: + enum {KStopBitMask = 1}; +public: + TPhysAddr iDescAddr; + TPhysAddr iSrcAddr; + TPhysAddr iDestAddr; + TUint32 iCmd; + }; + + +////////////////////////////////////////////////////////////////////////////// +// Test Support +////////////////////////////////////////////////////////////////////////////// + +/** +TO DO: Fill in to provide information to the V1 test harness (t_dma.exe) +*/ +TDmaTestInfo TestInfo = + { + 0, + 0, + 0, + 0, + NULL, + 0, + NULL, + 0, + NULL + }; + + +EXPORT_C const TDmaTestInfo& DmaTestInfo() +// +// +// + { + return TestInfo; + } + +/** +TO DO: Fill in to provide information to the V2 test harness (t_dma2.exe) +*/ +TDmaV2TestInfo TestInfov2 = + { + 0, + 0, + 0, + 0, + {0}, + 0, + {0}, + 1, + {0} + }; + +EXPORT_C const TDmaV2TestInfo& DmaTestInfoV2() + { + return TestInfov2; + } + + +////////////////////////////////////////////////////////////////////////////// +// Simulated channel +////////////////////////////////////////////////////////////////////////////// + +class MSimChannel + { +public: + virtual void PreOpen() {} + }; + +////////////////////////////////////////////////////////////////////////////// +// Derived Channel (Scatter/Gather) +////////////////////////////////////////////////////////////////////////////// + +const SDmacCaps KSimSgChanCaps = + {0, // TInt iChannelPriorities; + EFalse, // TBool iChannelPauseAndResume; + EFalse, // TBool iAddrAlignedToElementSize; + EFalse, // TBool i1DIndexAddressing; + EFalse, // TBool i2DIndexAddressing; + KDmaSyncAuto, // TUint iSynchronizationTypes; + KDmaBurstSizeAny, // TUint iBurstTransactions; + EFalse, // TBool iDescriptorInterrupt; + EFalse, // TBool iFrameInterrupt; + EFalse, // TBool iLinkedListPausedInterrupt; + EFalse, // TBool iEndiannessConversion; + KDmaGraphicsOpNone, // TUint iGraphicsOps; + EFalse, // TBool iRepeatingTransfers; + EFalse, // TBool iChannelLinking; + ETrue, // TBool iHwDescriptors; + EFalse, // TBool iSrcDstAsymmetry; + EFalse, // TBool iAsymHwDescriptors; + EFalse, // TBool iBalancedAsymSegments; + EFalse, // TBool iAsymCompletionInterrupt; + EFalse, // TBool iAsymDescriptorInterrupt; + EFalse, // TBool iAsymFrameInterrupt; + {0, 0, 0, 0, 0} // TUint32 iReserved[5]; + }; + +const SDmacCaps KSimSwChanCaps = + {0, // TInt iChannelPriorities; + EFalse, // TBool iChannelPauseAndResume; + EFalse, // TBool iAddrAlignedToElementSize; + EFalse, // TBool i1DIndexAddressing; + EFalse, // TBool i2DIndexAddressing; + KDmaSyncAuto, // TUint iSynchronizationTypes; + KDmaBurstSizeAny, // TUint iBurstTransactions; + EFalse, // TBool iDescriptorInterrupt; + EFalse, // TBool iFrameInterrupt; + EFalse, // TBool iLinkedListPausedInterrupt; + EFalse, // TBool iEndiannessConversion; + KDmaGraphicsOpNone, // TUint iGraphicsOps; + EFalse, // TBool iRepeatingTransfers; + EFalse, // TBool iChannelLinking; + EFalse, // TBool iHwDescriptors; + EFalse, // TBool iSrcDstAsymmetry; + EFalse, // TBool iAsymHwDescriptors; + EFalse, // TBool iBalancedAsymSegments; + EFalse, // TBool iAsymCompletionInterrupt; + EFalse, // TBool iAsymDescriptorInterrupt; + EFalse, // TBool iAsymFrameInterrupt; + {0, 0, 0, 0, 0} // TUint32 iReserved[5]; + }; + +class TEmptyChannel : public TDmaChannel, public MSimChannel + { +public: + // Virtual from TDmaChannel + void DoCancelAll(); + + void CallDefaultVirtuals(); + + // From MSimChannel + void PreOpen(); + }; + +void TEmptyChannel::DoCancelAll() + { + __DMA_CANT_HAPPEN(); + } + +void TEmptyChannel::CallDefaultVirtuals() + { + DMA_PSL_TRACE("Calling default virtual TDmaChannel functions"); + + const DDmaRequest* req = NULL; + SDmaDesHdr* hdr = NULL; + + DoQueue(*req); + DoDfc(*req, hdr); + DoDfc(*req, hdr, hdr); + + QueuedRequestCountChanged(); + } + +void TEmptyChannel::PreOpen() + { + CallDefaultVirtuals(); + } + +////////////////////////////////////////////////////////////////////////////// +// Derived SkelControllerSw Class +////////////////////////////////////////////////////////////////////////////// + +class TSkelDmac : public TDmac + { +public: + TSkelDmac(const SCreateInfo& aInfo); + TInt Create(const SCreateInfo& aInfo); +private: + // from TDmac (PIL pure virtual) + virtual void StopTransfer(const TDmaChannel& aChannel); + virtual TBool IsIdle(const TDmaChannel& aChannel); + virtual TUint MaxTransferLength(TDmaChannel& aChannel, TUint aSrcFlags, + TUint aDstFlags, TUint32 aPslInfo); + virtual TUint AddressAlignMask(TDmaChannel& aChannel, TUint aSrcFlags, + TUint aDstFlags, TUint32 aPslInfo); + + inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr); + + void CallDefaultVirtuals(); + TInt TestPool(); + +public: + static const SCreateInfo KDmacInfoHw; + static const SCreateInfo KDmacInfoSw; + + TEmptyChannel iChannel; + }; + + +const TDmac::SCreateInfo TSkelDmac::KDmacInfoHw = + { + ETrue, // iCapsHwDes + KDesCount, // iDesCount + sizeof(TDmaDesc), // iDesSize +#ifndef __WINS__ + EMapAttrSupRw | EMapAttrFullyBlocking // iDesChunkAttribs +#endif + }; + +const TDmac::SCreateInfo TSkelDmac::KDmacInfoSw = + { + EFalse, // iCapsHwDes + KDesCount, // iDesCount + sizeof(TDmaTransferArgs), // iDesSize +#ifndef __WINS__ + EMapAttrSupRw | EMapAttrFullyBlocking // iDesChunkAttribs +#endif + }; + +static TSkelDmac SkelControllerSw(TSkelDmac::KDmacInfoSw); +static TSkelDmac SkelControllerHw(TSkelDmac::KDmacInfoHw); + + +TSkelDmac::TSkelDmac(const SCreateInfo& aInfo) +// +// Constructor. +// + : TDmac(aInfo) + { + // TODO remove this once DMAC can be created and destroyed from test LDD entry + // point + TInt r = Create(aInfo); + __NK_ASSERT_ALWAYS(r == KErrNone); + + CallDefaultVirtuals(); + r = TestPool(); + __NK_ASSERT_ALWAYS(r == KErrNone); + } + + +TInt TSkelDmac::Create(const SCreateInfo& aInfo) +// +// Second phase construction. +// + { + TInt r = TDmac::Create(aInfo); // Base class Create() + if (r == KErrNone) + { + __DMA_ASSERTA(ReserveSetOfDes(1) == KErrNone); + } + return r; + } + + +void TSkelDmac::StopTransfer(const TDmaChannel& aChannel) +// +// Stops a running channel. +// + { + const TUint8 i = static_cast(aChannel.PslId()); + + __KTRACE_OPT(KDMA, Kern::Printf(">TSkelDmac::StopTransfer channel=%d (unsupported)", i)); + + (void) i; + + } + + +TBool TSkelDmac::IsIdle(const TDmaChannel& aChannel) +// +// Returns the state of a given channel. +// + { + const TUint8 i = static_cast(aChannel.PslId()); + + __KTRACE_OPT(KDMA, Kern::Printf(">TSkelDmac::IsIdle channel=%d (unsupported)", i)); + + // TO DO (for instance): Return the state of the RUN bit of the channel. + // The return value should reflect the actual state. + (void) i; + + return ETrue; + } + + +TUint TSkelDmac::MaxTransferLength(TDmaChannel& /*aChannel*/, TUint /*aSrcFlags*/, + TUint /*aDstFlags*/, TUint32 /*aPslInfo*/) +// +// Returns the maximum transfer length in bytes for a given transfer. +// + { + // TO DO: Determine the proper return value, based on the arguments. + + // For instance: + return KMaxTransferLen; + } + + +TUint TSkelDmac::AddressAlignMask(TDmaChannel& /*aChannel*/, TUint /*aSrcFlags*/, + TUint /*aDstFlags*/, TUint32 /*aPslInfo*/) +// +// Returns the memory buffer alignment restrictions mask for a given transfer. +// + { + // TO DO: Determine the proper return value, based on the arguments. + + // For instance: + return KMemAlignMask; + } + + +inline TDmaDesc* TSkelDmac::HdrToHwDes(const SDmaDesHdr& aHdr) +// +// Changes return type of base class call. +// + { + return static_cast(TDmac::HdrToHwDes(aHdr)); + } + +/** +Call the default virtual functions on the TDmac, +that would never otherwise be called + +*/ +void TSkelDmac::CallDefaultVirtuals() + { + DMA_PSL_TRACE("Calling default virtual TDmac functions"); + + TDmaChannel* channel = NULL; + SDmaDesHdr* hdr = NULL; + + Transfer(*channel, *hdr); + Transfer(*channel, *hdr, *hdr); + + const TDmaTransferArgs args; + TInt r = KErrNone; + + r = InitHwDes(*hdr, args); + __NK_ASSERT_ALWAYS(r == KErrGeneral); + + r = InitSrcHwDes(*hdr, args); + __NK_ASSERT_ALWAYS(r == KErrGeneral); + + r = InitDstHwDes(*hdr, args); + __NK_ASSERT_ALWAYS(r == KErrGeneral); + + r = UpdateHwDes(*hdr, KPhysAddrInvalid, KPhysAddrInvalid, 0, 0); + __NK_ASSERT_ALWAYS(r == KErrGeneral); + + r = UpdateSrcHwDes(*hdr, KPhysAddrInvalid, 0, 0); + __NK_ASSERT_ALWAYS(r == KErrGeneral); + + r = UpdateDstHwDes(*hdr, KPhysAddrInvalid, 0, 0); + __NK_ASSERT_ALWAYS(r == KErrGeneral); + + ChainHwDes(*hdr, *hdr); + AppendHwDes(*channel, *hdr, *hdr); + AppendHwDes(*channel, *hdr, *hdr, *hdr, *hdr); + UnlinkHwDes(*channel, *hdr); + + TUint32 count = 0; + + count = HwDesNumDstElementsTransferred(*hdr); + __NK_ASSERT_ALWAYS(count == 0); + + count = HwDesNumSrcElementsTransferred(*hdr); + __NK_ASSERT_ALWAYS(count == 0); + } + +TInt TSkelDmac::TestPool() + { + DMA_PSL_TRACE("TSkelDmac::TestPool()"); + TInt count = 0; + SDmaDesHdr* hdr = iFreeHdr; + TAny* des = iDesPool; + + TInt r = KErrNone; + while(hdr->iNext) + { + TAny* receivedDes = NULL; + if(iCapsHwDes) + { + receivedDes = HdrToHwDes(*hdr); + } + else + { + TDmaTransferArgs& args = HdrToDes(*hdr); + receivedDes = &args; + } + + if(receivedDes != des) + { + DMA_PSL_TRACE1("TSkelDmac::TestPool() failure: count=%d", count); + r = KErrGeneral; + break; + } + + hdr = hdr->iNext; + des = (TAny*)((TUint)des + iDesSize); + count++; + } + + if(count != (KDesCount - 1)) + { + DMA_PSL_TRACE2("TSkelDmac::TestPool() failure: count = %d != (iMaxDesCount -1) = %d", count, KDesCount-1); + r = KErrUnknown; + } + return r; + } + +////////////////////////////////////////////////////////////////////////////// +// Simulated Fragmentation Dmac +////////////////////////////////////////////////////////////////////////////// + + +const SDmacCaps KSimAsymmChanCaps = + {0, // TInt iChannelPriorities; + EFalse, // TBool iChannelPauseAndResume; + EFalse, // TBool iAddrAlignedToElementSize; + EFalse, // TBool i1DIndexAddressing; + EFalse, // TBool i2DIndexAddressing; + KDmaSyncAuto, // TUint iSynchronizationTypes; + KDmaBurstSizeAny, // TUint iBurstTransactions; + EFalse, // TBool iDescriptorInterrupt; + EFalse, // TBool iFrameInterrupt; + EFalse, // TBool iLinkedListPausedInterrupt; + EFalse, // TBool iEndiannessConversion; + KDmaGraphicsOpNone, // TUint iGraphicsOps; + EFalse, // TBool iRepeatingTransfers; + EFalse, // TBool iChannelLinking; + ETrue, // TBool iHwDescriptors; + EFalse, // TBool iSrcDstAsymmetry; + ETrue, // TBool iAsymHwDescriptors; + EFalse, // TBool iBalancedAsymSegments; + EFalse, // TBool iAsymCompletionInterrupt; + EFalse, // TBool iAsymDescriptorInterrupt; + EFalse, // TBool iAsymFrameInterrupt; + {0, 0, 0, 0, 0} // TUint32 iReserved[5]; + }; + +const SDmacCaps KSimAsymmBalancedChanCaps = + {0, // TInt iChannelPriorities; + EFalse, // TBool iChannelPauseAndResume; + EFalse, // TBool iAddrAlignedToElementSize; + EFalse, // TBool i1DIndexAddressing; + EFalse, // TBool i2DIndexAddressing; + KDmaSyncAuto, // TUint iSynchronizationTypes; + KDmaBurstSizeAny, // TUint iBurstTransactions; + EFalse, // TBool iDescriptorInterrupt; + EFalse, // TBool iFrameInterrupt; + EFalse, // TBool iLinkedListPausedInterrupt; + EFalse, // TBool iEndiannessConversion; + KDmaGraphicsOpNone, // TUint iGraphicsOps; + EFalse, // TBool iRepeatingTransfers; + EFalse, // TBool iChannelLinking; + ETrue, // TBool iHwDescriptors; + EFalse, // TBool iSrcDstAsymmetry; + ETrue, // TBool iAsymHwDescriptors; + ETrue, // TBool iBalancedAsymSegments; + EFalse, // TBool iAsymCompletionInterrupt; + EFalse, // TBool iAsymDescriptorInterrupt; + EFalse, // TBool iAsymFrameInterrupt; + {0, 0, 0, 0, 0} // TUint32 iReserved[5]; + }; + + +class TAsymmDmac : public TDmac + { + struct THwDes + { + TUint iAddr; + TUint iLength; + TUint iCookie; + }; +public: + TAsymmDmac(); + TInt Create(); +private: + // Work around for compiler which forbids this + // class from accessing the protected, nested TDmac::SCreateInfo + using TDmac::SCreateInfo; + + // from TDmac (PIL pure virtual) + virtual void StopTransfer(const TDmaChannel& aChannel); + virtual TBool IsIdle(const TDmaChannel& aChannel); + virtual TUint MaxTransferLength(TDmaChannel& aChannel, TUint aSrcFlags, + TUint aDstFlags, TUint32 aPslInfo); + virtual TUint AddressAlignMask(TDmaChannel& aChannel, TUint aSrcFlags, + TUint aDstFlags, TUint32 aPslInfo); + // from TDmac (PIL virtual) + TInt InitSrcHwDes(const SDmaDesHdr& /*aHdr*/, const TDmaTransferArgs& /*aTransferArgs*/); + TInt InitDstHwDes(const SDmaDesHdr& /*aHdr*/, const TDmaTransferArgs& /*aTransferArgs*/); + + void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr); + void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr); + + inline THwDes* HdrToHwDes(const SDmaDesHdr& aHdr); + +private: + static const SCreateInfo KInfo; +public: + static const TInt iChannelCount; + TEmptyChannel iChannel; + }; + +const TAsymmDmac::SCreateInfo TAsymmDmac::KInfo = + { + ETrue, // iCapsHwDes + KDesCount, // iDesCount + sizeof(THwDes), // iDesSize +#ifndef __WINS__ + EMapAttrSupRw | EMapAttrFullyBlocking // iDesChunkAttribs +#endif + }; + +const TInt TAsymmDmac::iChannelCount = 1; + +static TAsymmDmac AsymController; + +TAsymmDmac::TAsymmDmac() +// +// Constructor. +// + : TDmac(KInfo) + { + // TODO remove this once DMAC can be created and destroyed from test LDD entry + // point + TInt r = Create(); + __NK_ASSERT_ALWAYS(r == KErrNone); + } + + +TInt TAsymmDmac::Create() +// +// Second phase construction. +// + { + TInt r = TDmac::Create(KInfo); // Base class Create() + if (r == KErrNone) + { + __DMA_ASSERTA(ReserveSetOfDes(iChannelCount) == KErrNone); + } + return r; + } + + +void TAsymmDmac::StopTransfer(const TDmaChannel& /*aChannel*/) +// +// Stops a running channel. +// + { + __DMA_CANT_HAPPEN(); + } + + +TBool TAsymmDmac::IsIdle(const TDmaChannel& /*aChannel*/) +// +// Returns the state of a given channel. +// + { + __DMA_CANT_HAPPEN(); + return ETrue; + } + + +TUint TAsymmDmac::MaxTransferLength(TDmaChannel& /*aChannel*/, TUint /*aSrcFlags*/, + TUint /*aDstFlags*/, TUint32 /*aPslInfo*/) +// +// Returns the maximum transfer length in bytes for a given transfer. +// + { + // TO DO: Determine the proper return value, based on the arguments. + + // For instance: + return KMaxTransferLen; + } + + +TUint TAsymmDmac::AddressAlignMask(TDmaChannel& /*aChannel*/, TUint /*aSrcFlags*/, + TUint /*aDstFlags*/, TUint32 /*aPslInfo*/) +// +// Returns the memory buffer alignment restrictions mask for a given transfer. +// + { + // TO DO: Determine the proper return value, based on the arguments. + + // For instance: + return KMemAlignMask; + } + + +inline TAsymmDmac::THwDes* TAsymmDmac::HdrToHwDes(const SDmaDesHdr& aHdr) +// +// Changes return type of base class call. +// + { + return static_cast(TDmac::HdrToHwDes(aHdr)); + } + +TInt TAsymmDmac::InitSrcHwDes(const SDmaDesHdr& /*aHdr*/, const TDmaTransferArgs& /*aTransferArgs*/) + { + return KErrNone; + } + +TInt TAsymmDmac::InitDstHwDes(const SDmaDesHdr& /*aHdr*/, const TDmaTransferArgs& /*aTransferArgs*/) + { + return KErrNone; + } + +void TAsymmDmac::ChainHwDes(const SDmaDesHdr& /*aHdr*/, const SDmaDesHdr& /*aNextHdr*/) + { + } + +void TAsymmDmac::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& /*aHdr*/) + { + } + + + +////////////////////////////////////////////////////////////////////////////// +// Channel Opening/Closing (Channel Allocator) +////////////////////////////////////////////////////////////////////////////// + +struct TChanEntry + { + TChanEntry(TDmac& aController, TDmaChannel& aChannel, const SDmacCaps& aCaps) + : + iController(aController), + iChannel(aChannel), + iCaps(aCaps) + {} + + TDmac& iController; + TDmaChannel& iChannel; + const SDmacCaps& iCaps; + }; + +const TChanEntry ChannelTable[] = + { + TChanEntry(SkelControllerSw, SkelControllerSw.iChannel, KSimSwChanCaps), + TChanEntry(SkelControllerHw, SkelControllerHw.iChannel, KSimSgChanCaps), + TChanEntry(AsymController, AsymController.iChannel, KSimAsymmChanCaps), + TChanEntry(AsymController, AsymController.iChannel, KSimAsymmBalancedChanCaps) + }; + +static const TInt KChannelCount = ARRAY_LENGTH(ChannelTable); + +TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId, TBool /*aDynChannel*/, TUint /*aPriority*/) +// +// +// + { + __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId)); + + __DMA_ASSERTA(aOpenId < static_cast(KChannelCount)); + + const TChanEntry& entry = ChannelTable[aOpenId]; + TDmaChannel* pC = &entry.iChannel; + if (pC->IsOpened()) + { + pC = NULL; + } + else + { + pC->iController = &entry.iController; + pC->iPslId = aOpenId; + pC->iDmacCaps = &entry.iCaps; + + // It is safe to signal here, + // setting iController marks the channel + // as taken + Signal(); + + static_cast(pC)->PreOpen(); + + Wait(); + } + return pC; + } + + +void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/) +// +// +// + { + // NOP + } + + +TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/) +// +// +// + { + return KErrNotSupported; + }