sl@0: // Copyright (c) 2006-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\debug\d_cache.cpp sl@0: // See e32test\mmu\t_cache.cpp for details sl@0: // sl@0: // sl@0: sl@0: #include "d_cache.h" sl@0: #include sl@0: #include sl@0: sl@0: extern TUint32 GetCacheType(); sl@0: extern void TestCodeFunc(); sl@0: extern TInt TestCodeFuncSize(); sl@0: extern void DataSegmetTestFunct(void* aBase, TInt aSize); sl@0: sl@0: #ifdef __XSCALE_L2_CACHE__ sl@0: extern TUint32 L2CacheTypeReg(); sl@0: #endif sl@0: sl@0: #if defined(__CPU_MEMORY_TYPE_REMAPPING) sl@0: extern TUint32 CtrlRegister(); sl@0: extern TUint32 PRRRRegister(); sl@0: extern TUint32 NRRRRegister(); sl@0: extern void SetPRRR(TUint32); sl@0: extern void SetNRRR(TUint32); sl@0: #endif sl@0: sl@0: sl@0: typedef void(CodeTest) (); sl@0: sl@0: class DCacheTest : public DLogicalChannelBase sl@0: { sl@0: public: sl@0: DCacheTest(); sl@0: ~DCacheTest(); sl@0: protected: 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: private: sl@0: TInt GetCacheInfo(TAny* a1); sl@0: TInt TestDataChunk(TAny* a1); sl@0: TInt TestCodeChunk(TAny* a1); sl@0: TInt TestWriteBackMode(TAny* a1, TBool aWriteAlloc); sl@0: TInt TestL2Maintenance(); sl@0: TInt GetThreshold(TAny* a1); sl@0: TInt SetThreshold(TAny* a1); sl@0: TInt TestUseCase(TAny* a1); sl@0: void LoopTestCodeFunc(CodeTest* f); sl@0: sl@0: sl@0: void GetExternalCacheInfo(RCacheTestDevice::TCacheInfo& info); sl@0: sl@0: void CheckRemapping(RCacheTestDevice::TCacheInfo& info); sl@0: void Remap(RCacheTestDevice::TCacheAttr aCacheAttr); sl@0: sl@0: TInt UseCase_ReadFromChunk(RCacheTestDevice::TChunkTest& info); sl@0: TInt UseCase_ReadFromChunk_ReadFromHeap(RCacheTestDevice::TChunkTest& info); sl@0: TInt UseCase_WriteToChunk(RCacheTestDevice::TChunkTest& info); sl@0: TInt UseCase_WriteToChunk_ReadFromHeap(RCacheTestDevice::TChunkTest& info); sl@0: sl@0: sl@0: //Phys. memory and shared chunk alloc/dealloc primitives sl@0: TInt AllocPhysicalRam(TInt aSize); sl@0: void FreePhysicalRam(); sl@0: TInt CreateSharedChunk(TInt aMapAttr, TUint32& aActualMapAttr); sl@0: void CloseSharedChunk(); sl@0: sl@0: private: sl@0: DChunk* iSharedChunk; // Shared chunk used in the test sl@0: TPhysAddr iPhysAddr; // Physical address of the allocated memory assigned to the chunk sl@0: TUint iSize; // The size of the allocated memory. sl@0: TLinAddr iChunkBase; // Base linear address of the shared chunk. sl@0: sl@0: TInt* iHeap1; sl@0: TInt* iHeap2; sl@0: TUint32 iDummy; sl@0: }; sl@0: sl@0: DCacheTest* CacheTestDriver; sl@0: sl@0: DCacheTest::DCacheTest() {} sl@0: sl@0: DCacheTest::~DCacheTest() {CacheTestDriver = NULL;} sl@0: sl@0: /**Creates the channel*/ sl@0: TInt DCacheTest::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/) {return KErrNone;} sl@0: sl@0: /** Allocates physical memory and sets iPhysAddr & iSize accordingly.*/ sl@0: TInt DCacheTest::AllocPhysicalRam(TInt aSize) sl@0: { sl@0: iSize = aSize; sl@0: NKern::ThreadEnterCS(); sl@0: TInt r = Epoc::AllocPhysicalRam(aSize, iPhysAddr, 0); //Allocate physical RAM. This will set iPhysAddr sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: /** Frees physical memory.*/ sl@0: void DCacheTest::FreePhysicalRam() sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: Epoc::FreePhysicalRam(iPhysAddr, iSize); sl@0: NKern::ThreadLeaveCS(); sl@0: } sl@0: sl@0: /** sl@0: Creates shared chunks with allocated physical memory and sets iChunkBase accordingly. sl@0: @pre Physical memory is allocated (iPhysAddr & iSize are set accordingly). sl@0: */ sl@0: TInt DCacheTest::CreateSharedChunk(TInt aMapAttr, TUint32& aActualMapAttr) sl@0: { sl@0: TInt r; sl@0: TChunkCreateInfo chunkInfo; sl@0: chunkInfo.iType = TChunkCreateInfo::ESharedKernelSingle; sl@0: chunkInfo.iMaxSize = iSize; sl@0: chunkInfo.iMapAttr = aMapAttr; sl@0: chunkInfo.iOwnsMemory = EFalse; sl@0: chunkInfo.iDestroyedDfc = NULL; sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: if (KErrNone != (r = Kern::ChunkCreate(chunkInfo, iSharedChunk, iChunkBase, aActualMapAttr))) sl@0: { sl@0: FreePhysicalRam(); sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: r = Kern::ChunkCommitPhysical(iSharedChunk,0,iSize, iPhysAddr); sl@0: if(r!=KErrNone) sl@0: { sl@0: CloseSharedChunk(); sl@0: FreePhysicalRam(); sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: NKern::ThreadLeaveCS(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** Closes shared chunk.*/ sl@0: void DCacheTest::CloseSharedChunk() sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: Kern::ChunkClose(iSharedChunk); sl@0: Kern::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0); // make sure async close has happened sl@0: NKern::ThreadLeaveCS(); sl@0: } sl@0: sl@0: sl@0: #if defined(__CPU_ARMV7) sl@0: extern TUint32 CacheTypeRegister(); sl@0: extern TUint32 CacheLevelIDRegister(); sl@0: extern TUint32 CacheSizeIdRegister(TUint32 aType/*0-1*/, TUint32 aLevel/*0-7*/); sl@0: sl@0: void ParseCacheLevelInfo(TInt aCacheSizeIDReg, RCacheTestDevice::TCacheSingle& aCS) sl@0: { sl@0: aCS.iSets = ((aCacheSizeIDReg>>13)& 0x7fff)+1; sl@0: aCS.iWays = ((aCacheSizeIDReg>>3)& 0x3ff)+1; sl@0: aCS.iLineSize =1<<((aCacheSizeIDReg & 0x7)+4);//+2 (and +2 as we count in bytes) sl@0: aCS.iSize = aCS.iSets * aCS.iWays * aCS.iLineSize; sl@0: } sl@0: #endif sl@0: sl@0: sl@0: void AppendTo(TDes8& aDes, const char* aFmt, ...) sl@0: { sl@0: VA_LIST list; sl@0: VA_START(list,aFmt); sl@0: Kern::AppendFormat(aDes,aFmt,list); sl@0: } sl@0: sl@0: /** Checks Memory Remap settings (both memory type and access permission remapping).*/ sl@0: void DCacheTest::CheckRemapping(RCacheTestDevice::TCacheInfo& info) sl@0: { sl@0: #if defined(__CPU_MEMORY_TYPE_REMAPPING) sl@0: TUint32 cr = CtrlRegister(); sl@0: TUint32 prrr =PRRRRegister(); sl@0: TUint32 nrrr =NRRRRegister(); sl@0: AppendTo(info.iDesc,"Memory Remapping: CtrlReg:%xH, PRRR:%xH NRRR:%xH\n", cr, prrr, nrrr); sl@0: sl@0: if ( (cr&0x30000000) == 0x30000000) sl@0: info.iMemoryRemapping = 1; sl@0: else sl@0: AppendTo(info.iDesc,"Error:Memory Remapping is OFF \n"); sl@0: #endif sl@0: } sl@0: sl@0: //Remaps aCacheAttr memory type into EMemAttKernelInternal4 sl@0: void DCacheTest::Remap(RCacheTestDevice::TCacheAttr aCacheAttr) sl@0: { sl@0: #if defined(__CPU_MEMORY_TYPE_REMAPPING) sl@0: TInt inner, outer; sl@0: switch(aCacheAttr) sl@0: { sl@0: case RCacheTestDevice::E_InnerWT_Remapped: inner=2;outer=0;break; sl@0: case RCacheTestDevice::E_InnerWBRA_Remapped:inner=3;outer=0;break; sl@0: case RCacheTestDevice::E_InnerWB_Remapped: inner=1;outer=0;break; sl@0: case RCacheTestDevice::E_OuterWT_Remapped: inner=0;outer=2;break; sl@0: case RCacheTestDevice::E_OuterWBRA_Remapped:inner=0;outer=3;break; sl@0: case RCacheTestDevice::E_OuterWB_Remapped: inner=0;outer=1;break; sl@0: case RCacheTestDevice::E_InOutWT_Remapped: inner=2;outer=2;break; sl@0: case RCacheTestDevice::E_InOutWBRA_Remapped:inner=3;outer=3;break; sl@0: case RCacheTestDevice::E_InOutWB_Remapped: inner=1;outer=1;break; sl@0: default:Kern::PanicCurrentThread(_L("d_cache driver error"),0);return; sl@0: } sl@0: sl@0: TUint32 prrr =PRRRRegister(); sl@0: TUint32 nrrr =NRRRRegister(); sl@0: prrr &= ~(3<<8); // Clear EMemAttKernelInternal4 setting for memory type sl@0: nrrr &= ~(3<<8); // Clear EMemAttKernelInternal4 setting for normal memory type, inner cache sl@0: nrrr &= ~(3<<24); // Clear EMemAttKernelInternal4 setting for normal memory type, outer cache sl@0: prrr |= 2 <<8; // Set EMemAttKernelInternal4 as normal memory sl@0: nrrr |= inner <<8; // Set inner cache for EMemAttKernelInternal4 sl@0: nrrr |= outer << 24;// Set outer cache for EMemAttKernelInternal4 sl@0: sl@0: SetPRRR(prrr); sl@0: SetNRRR(nrrr); sl@0: #endif sl@0: } sl@0: sl@0: sl@0: sl@0: /** Fills in info structure with external cache parameters. */ sl@0: void DCacheTest::GetExternalCacheInfo(RCacheTestDevice::TCacheInfo& info) sl@0: { sl@0: #if defined(__HAS_EXTERNAL_CACHE__) sl@0: info.iOuterCache=1; sl@0: sl@0: #if defined(__ARM_L210_CACHE__) sl@0: AppendTo(info.iDesc,"Built as L210 Cache;\n"); sl@0: #elif defined(__ARM_L220_CACHE__) sl@0: AppendTo(info.iDesc,"Built as L220 Cache:\n"); sl@0: #elif defined(__ARM_PL310_CACHE__) sl@0: AppendTo(info.iDesc,"Built as PL310 Cache:\n"); sl@0: #endif sl@0: sl@0: TInt cacheController = Kern::SuperPage().iArmL2CacheBase; sl@0: if (!cacheController) sl@0: { sl@0: AppendTo(info.iDesc,"Warning:No CCB Address in Super Page?\n"); sl@0: return; sl@0: } sl@0: sl@0: TInt rawData = *(TInt*)(cacheController); //reg 0 in controller is Cache ID Register sl@0: AppendTo(info.iDesc,"L2 ID Reg:%xH\n", rawData); sl@0: sl@0: rawData = *(TInt*)(cacheController+4); //reg 4 in controller is Cache Type Register sl@0: AppendTo(info.iDesc,"L2 Type Reg:%xH\n", rawData); sl@0: sl@0: RCacheTestDevice::TCacheSingle& cs = info.iCache[info.iCacheCount]; sl@0: sl@0: cs.iLineSize=32; //always sl@0: #if defined(__ARM_L210_CACHE__) || defined(__ARM_L220_CACHE__) sl@0: cs.iWays = (rawData>>3)&0x0f; if (cs.iWays > 8) cs.iWays = 8; sl@0: #elif defined(__ARM_PL310_CACHE__) sl@0: cs.iWays = (rawData&0x40) ? 16:8; sl@0: #endif sl@0: TInt waySize; sl@0: switch((rawData>>8)&7) sl@0: { sl@0: case 0: waySize = 0x4000; break; sl@0: case 1: waySize = 0x4000; break; sl@0: case 2: waySize = 0x8000; break; sl@0: case 3: waySize = 0x10000; break; sl@0: case 4: waySize = 0x20000; break; sl@0: #if defined(__ARM_L210_CACHE__) || defined(__ARM_L220_CACHE__) sl@0: default: waySize = 0x40000; break; sl@0: #elif defined(__ARM_PL310_CACHE__) sl@0: case 5: waySize = 0x40000; break; sl@0: default: waySize = 0x80000; break; sl@0: #endif sl@0: } sl@0: cs.iSize = waySize * cs.iWays; sl@0: cs.iSets = waySize >> 5; // = waySize / lineLen sl@0: sl@0: sl@0: cs.iLevel = 2; sl@0: cs.iCode = 1; sl@0: cs.iData = 1; sl@0: cs.iDesc.SetLength(0); sl@0: AppendTo(cs.iDesc,"Outer Unified PAPT"); sl@0: sl@0: info.iMaxCacheSize = Max(info.iMaxCacheSize, cs.iSize); sl@0: info.iCacheCount++; sl@0: #endif //defined(__HAS_EXTERNAL_CACHE__) sl@0: } sl@0: sl@0: sl@0: /** Passes cache configuration parameters to the user side*/ sl@0: TInt DCacheTest::GetCacheInfo(TAny* a1) sl@0: { sl@0: TInt ret = KErrNone; sl@0: RCacheTestDevice::TCacheInfo info; sl@0: sl@0: info.iDesc.SetLength(0); sl@0: info.iCacheCount=0; sl@0: info.iMaxCacheSize=0; sl@0: info.iMemoryRemapping=0; sl@0: info.iOuterCache=0; sl@0: sl@0: //////////////////////// sl@0: #if defined(__CPU_ARMV7) sl@0: //////////////////////// sl@0: info.iOuterCache=1; sl@0: sl@0: TUint32 ctr=CacheTypeRegister(); sl@0: TUint32 clr=CacheLevelIDRegister(); sl@0: TInt LoC = (clr>>24)&7; //The number of levels to be purged/clean to Point-to-Coherency sl@0: TInt LoU = (clr>>27)&7; //The number of levels to be purged/clean to Point-to-Unification sl@0: AppendTo(info.iDesc,"ARMv7 cache - CTR:%xH CLR:%xH LoC:%d LoU:%d\n", ctr, clr, LoC, LoU); sl@0: sl@0: RCacheTestDevice::TCacheSingle* cs = &info.iCache[info.iCacheCount]; sl@0: TInt level; sl@0: for (level=0;level> (level*3)) & 7; //000:NoCache 001:ICache 010:DCache 011:Both 100:Unified sl@0: sl@0: if (type==0) // No Cache. Also no cache below this level sl@0: break; sl@0: sl@0: if(type & 1) // Instruction Cache sl@0: { sl@0: TInt csr = CacheSizeIdRegister(1,level); sl@0: ParseCacheLevelInfo(csr, *cs); sl@0: cs->iLevel = level+1; sl@0: cs->iCode = 1; sl@0: cs->iData = 0; sl@0: AppendTo(cs->iDesc,"ICache CSR:%xH",csr); sl@0: info.iMaxCacheSize = Max(info.iMaxCacheSize, cs->iSize); sl@0: cs = &info.iCache[++info.iCacheCount]; sl@0: } sl@0: sl@0: if(type & 2) // Data Cache sl@0: { sl@0: TInt csr = CacheSizeIdRegister(0,level); sl@0: ParseCacheLevelInfo(csr, *cs); sl@0: cs->iLevel = level+1; sl@0: cs->iCode = 0; sl@0: cs->iData = 1; sl@0: AppendTo(cs->iDesc,"DCache CSR:%xH",csr); sl@0: info.iMaxCacheSize = Max(info.iMaxCacheSize, cs->iSize); sl@0: cs = &info.iCache[++info.iCacheCount]; sl@0: } sl@0: sl@0: if(type & 4) // Unified Cache sl@0: { sl@0: TInt csr = CacheSizeIdRegister(0,level); sl@0: ParseCacheLevelInfo(csr, *cs); sl@0: cs->iLevel = level+1; sl@0: cs->iCode = 1; sl@0: cs->iData = 1; sl@0: AppendTo(cs->iDesc,"Unified CSR:%xH",csr); sl@0: info.iMaxCacheSize = Max(info.iMaxCacheSize, cs->iSize); sl@0: cs = &info.iCache[++info.iCacheCount]; sl@0: } sl@0: } sl@0: sl@0: /////////////////////////////////// sl@0: #elif defined(__CPU_HAS_CACHE_TYPE_REGISTER) sl@0: /////////////////////////////////// sl@0: sl@0: TInt rawData=GetCacheType(); sl@0: TInt splitCache=rawData&0x01000000; sl@0: AppendTo(info.iDesc,"L1 Cache TypeReg=%xH\n", rawData); sl@0: sl@0: //Cache #1 sl@0: TUint32 s=(rawData>>12)&0xfff; //s = P[11]:0:size[9:5]:assoc[5:3]:M[2]:len[1:0] sl@0: info.iCache[info.iCacheCount].iLineSize = 1 << ((s&2) + 3); //1<<(len+3) sl@0: info.iCache[info.iCacheCount].iWays = (2 + ((s>>2)&1)) << (((s>>3)&0x7) - 1); //(2+M) << (assoc-1) sl@0: info.iCache[info.iCacheCount].iSize = (2 + ((s>>2)&1)) << (((s>>6)&0xf) + 8); //(2+M) << (size+8) sl@0: info.iCache[info.iCacheCount].iSets = 1 << (((s>>6)&0xf) + 6 - ((s>>3)&0x7) - (s&2)); //(2+M) <<(size + 6 -assoc - len) sl@0: info.iCache[info.iCacheCount].iData = 1; sl@0: info.iCache[info.iCacheCount].iLevel = 1; sl@0: sl@0: if (splitCache) sl@0: { sl@0: info.iCache[info.iCacheCount].iCode = 0; sl@0: info.iCache[info.iCacheCount].iDesc.SetLength(0); sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc,"Inner DCache"); sl@0: sl@0: #if defined(__CPU_ARMV6) sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc," VAPT"); sl@0: #else sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc," VAVT"); sl@0: #endif sl@0: info.iMaxCacheSize = Max(info.iMaxCacheSize, info.iCache[info.iCacheCount].iSize); sl@0: info.iCacheCount++; sl@0: sl@0: // Cache #2 sl@0: s=rawData&0xfff; //s = P[11]:0:size[9:5]:assoc[5:3]:M[2]:len[1:0] sl@0: info.iCache[info.iCacheCount].iLineSize = 1 << ((s&2) + 3); //1<<(len+3) sl@0: info.iCache[info.iCacheCount].iWays = (2 + ((s>>2)&1)) << (((s>>3)&0x7) - 1); //(2+M) << (assoc-1) sl@0: info.iCache[info.iCacheCount].iSize = (2 + ((s>>2)&1)) << (((s>>6)&0xf) + 8); //(2+M) << (size+8) sl@0: info.iCache[info.iCacheCount].iSets = 1 << (((s>>6)&0xf) + 6 - ((s>>3)&0x7) - (s&2)); //(2+M) <<(size + 6 -assoc - len) sl@0: info.iCache[info.iCacheCount].iLevel = 1; sl@0: info.iCache[info.iCacheCount].iCode = 1; sl@0: info.iCache[info.iCacheCount].iData = 0; sl@0: info.iCache[info.iCacheCount].iDesc.SetLength(0); sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc,"Inner ICache"); sl@0: #if defined(__CPU_ARMV6) sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc," VAPT"); sl@0: #else sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc," VAVT"); sl@0: #endif sl@0: } sl@0: else sl@0: { sl@0: info.iCache[info.iCacheCount].iCode = 1; sl@0: info.iCache[info.iCacheCount].iDesc.SetLength(0); sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc,"Inner Unified"); sl@0: #if defined(__CPU_ARMV6) sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc," VAPT"); sl@0: #else sl@0: AppendTo(info.iCache[info.iCacheCount].iDesc," VAVT"); sl@0: #endif sl@0: } sl@0: info.iMaxCacheSize = Max(info.iMaxCacheSize, info.iCache[info.iCacheCount].iSize); sl@0: info.iCacheCount++; sl@0: sl@0: ///// sl@0: #else sl@0: ///// sl@0: sl@0: ret = KErrNotSupported; sl@0: sl@0: #endif sl@0: sl@0: GetExternalCacheInfo(info); // Get ARMl210/20 info sl@0: CheckRemapping(info); // Get memory remapping info sl@0: sl@0: info.iDmaBufferAlignment = Cache::DmaBufferAlignment(); sl@0: kumemput(a1,&info,sizeof(info)); sl@0: return ret; sl@0: } sl@0: sl@0: /** Get cache thresholds.*/ sl@0: TInt DCacheTest::GetThreshold(TAny* a1) sl@0: { sl@0: RCacheTestDevice::TThresholdInfo info; sl@0: kumemget(&info,a1,sizeof(info)); sl@0: sl@0: TCacheThresholds thresholds; sl@0: TInt r = Cache::GetThresholds(thresholds, info.iCacheType); sl@0: if (r==KErrNone) sl@0: { sl@0: info.iPurge = thresholds.iPurge; sl@0: info.iClean = thresholds.iClean; sl@0: info.iFlush = thresholds.iFlush; sl@0: kumemput(a1,&info,sizeof(info)); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: /** Set cache thresholds.*/ sl@0: TInt DCacheTest::SetThreshold(TAny* a1) sl@0: { sl@0: RCacheTestDevice::TThresholdInfo info; sl@0: kumemget(&info,a1,sizeof(info)); sl@0: sl@0: TCacheThresholds thresholds; sl@0: thresholds.iPurge = info.iPurge; sl@0: thresholds.iClean = info.iClean; sl@0: thresholds.iFlush = info.iFlush; sl@0: return Cache::SetThresholds(thresholds, info.iCacheType); sl@0: } sl@0: sl@0: // Runs DataSegmetTestFunct against data from a chunk. sl@0: // Chunk cache attributes and its size are specified in input arguments. sl@0: // Measures and returns the time spent. sl@0: TInt DCacheTest::TestDataChunk(TAny* a1) sl@0: { sl@0: TInt r = KErrNone; sl@0: TInt time; sl@0: sl@0: RCacheTestDevice::TChunkTest info; sl@0: kumemget(&info,a1,sizeof(info)); sl@0: sl@0: sl@0: TUint32 chunkAttr = EMapAttrSupRw; sl@0: if (info.iShared) chunkAttr |= EMapAttrShared; sl@0: #ifdef __SMP__ sl@0: TUint32 force_shared = EMapAttrShared; sl@0: #else sl@0: TUint32 force_shared = 0; sl@0: #endif sl@0: sl@0: switch (info.iCacheAttr) sl@0: { sl@0: sl@0: case RCacheTestDevice::E_FullyBlocking: chunkAttr |= EMapAttrFullyBlocking; break; sl@0: case RCacheTestDevice::E_Buffered_NC: chunkAttr |= EMapAttrBufferedNC; break; sl@0: case RCacheTestDevice::E_Buffered_C: chunkAttr |= EMapAttrBufferedC; break; sl@0: sl@0: case RCacheTestDevice::E_InnerWT: chunkAttr |= EMapAttrCachedWTRA|force_shared; break; sl@0: case RCacheTestDevice::E_InnerWBRA: chunkAttr |= EMapAttrCachedWBRA|force_shared; break; sl@0: case RCacheTestDevice::E_InnerWB: chunkAttr |= EMapAttrCachedWBWA|force_shared; break; sl@0: sl@0: case RCacheTestDevice::E_OuterWT: chunkAttr |= EMapAttrL2CachedWTRA; break; sl@0: case RCacheTestDevice::E_OuterWBRA: chunkAttr |= EMapAttrL2CachedWBRA; break; sl@0: case RCacheTestDevice::E_OuterWB: chunkAttr |= EMapAttrL2CachedWBWA; break; sl@0: sl@0: case RCacheTestDevice::E_InOutWT: chunkAttr |= EMapAttrCachedWTRA|EMapAttrL2CachedWTRA|force_shared; break; sl@0: case RCacheTestDevice::E_InOutWBRA: chunkAttr |= EMapAttrCachedWBRA|EMapAttrL2CachedWBRA|force_shared; break; sl@0: case RCacheTestDevice::E_InOutWB: chunkAttr |= EMapAttrCachedWBWA|EMapAttrL2CachedWBWA|force_shared; break; sl@0: sl@0: case RCacheTestDevice::E_StronglyOrder: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttStronglyOrdered,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Device: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttDevice,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Normal_Uncached: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttNormalUncached,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Normal_Cached: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttNormalCached,EFalse,ETrue,EFalse,(info.iShared|force_shared)?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_KernelInternal4: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,ETrue,(info.iShared|force_shared)?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_PlatformSpecific5: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttPlatformSpecific5,EFalse,ETrue,ETrue,(info.iShared|force_shared)?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_PlatformSpecific6: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttPlatformSpecific6,EFalse,ETrue,ETrue,(info.iShared|force_shared)?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_PlatformSpecific7: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttPlatformSpecific7,EFalse,ETrue,ETrue,(info.iShared|force_shared)?ETrue:EFalse); sl@0: break; sl@0: sl@0: #if defined(__CPU_MEMORY_TYPE_REMAPPING) sl@0: case RCacheTestDevice::E_InnerWT_Remapped: sl@0: case RCacheTestDevice::E_InnerWBRA_Remapped: sl@0: case RCacheTestDevice::E_InnerWB_Remapped: sl@0: case RCacheTestDevice::E_InOutWT_Remapped: sl@0: case RCacheTestDevice::E_InOutWBRA_Remapped: sl@0: case RCacheTestDevice::E_InOutWB_Remapped: sl@0: #ifdef __SMP__ sl@0: info.iShared = ETrue; sl@0: #endif sl@0: case RCacheTestDevice::E_OuterWT_Remapped: sl@0: case RCacheTestDevice::E_OuterWBRA_Remapped: sl@0: case RCacheTestDevice::E_OuterWB_Remapped: sl@0: Remap(info.iCacheAttr); sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse); sl@0: break; sl@0: #endif sl@0: sl@0: case RCacheTestDevice::E_Default: sl@0: { sl@0: // Run the test against memory from kernel heap (no need for extra memory chunks) sl@0: NKern::ThreadEnterCS(); sl@0: TLinAddr bufferBase = (TLinAddr)Kern::Alloc(info.iSize); sl@0: NKern::ThreadLeaveCS(); sl@0: if (!bufferBase) sl@0: return KErrNoMemory; sl@0: sl@0: //You can't purge allocated heap memory as it will invalidate other data from the same cache line. sl@0: //Cache::SyncMemoryAfterDmaRead((TLinAddr)bufferBase, info.iSize); sl@0: sl@0: // Execute the test sl@0: time = NKern::TickCount(); sl@0: DataSegmetTestFunct((void*)bufferBase, info.iSize); sl@0: info.iTime = NKern::TickCount() - time; sl@0: info.iActualMapAttr = 0; sl@0: kumemput(a1,&info,sizeof(info)); sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: Kern::Free((TAny*)bufferBase); sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: return KErrNone; sl@0: } sl@0: default: sl@0: return KErrArgument; sl@0: } sl@0: sl@0: // Run the test against chunk with cache attributes as specified in info.iCacheState. sl@0: if (KErrNone!=(r=AllocPhysicalRam(Kern::RoundToPageSize(info.iSize)))) return r; sl@0: if (KErrNone!=(r=CreateSharedChunk(chunkAttr, info.iActualMapAttr))) return r; sl@0: sl@0: Cache::SyncMemoryAfterDmaRead(iChunkBase, info.iSize); // Invalidate (aka purge) cache. sl@0: sl@0: time = NKern::TickCount(); sl@0: DataSegmetTestFunct((void*)iChunkBase, info.iSize); sl@0: info.iTime = NKern::TickCount() - time; sl@0: sl@0: CloseSharedChunk(); sl@0: FreePhysicalRam(); sl@0: sl@0: kumemput(a1,&info,sizeof(info)); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DCacheTest::LoopTestCodeFunc(CodeTest* f) sl@0: { sl@0: for (TInt x = 0;x<5000;x++) sl@0: (*f)(); sl@0: } sl@0: sl@0: // Runs TestCodeFunc (contains nops with ret at the end) from a chunk. sl@0: // Chunk cache attributes and the size of function are specified in input arguments sl@0: // Measures and returns the time spent. sl@0: TInt DCacheTest::TestCodeChunk(TAny* a1) sl@0: { sl@0: TInt r = KErrNone; sl@0: TInt time; sl@0: sl@0: RCacheTestDevice::TChunkTest info; sl@0: kumemget(&info,a1,sizeof(info)); sl@0: sl@0: sl@0: info.iActualMapAttr = EMapAttrSupRwx; sl@0: if (info.iShared) info.iActualMapAttr |= EMapAttrShared; sl@0: #ifdef __SMP__ sl@0: TUint32 force_shared = EMapAttrShared; sl@0: #else sl@0: TUint32 force_shared = 0; sl@0: #endif sl@0: sl@0: switch (info.iCacheAttr) sl@0: { sl@0: case RCacheTestDevice::E_FullyBlocking: info.iActualMapAttr |= EMapAttrFullyBlocking; break; sl@0: case RCacheTestDevice::E_Buffered_NC: info.iActualMapAttr |= EMapAttrBufferedNC; break; sl@0: case RCacheTestDevice::E_Buffered_C: info.iActualMapAttr |= EMapAttrBufferedC; break; sl@0: sl@0: case RCacheTestDevice::E_InnerWT: info.iActualMapAttr |= EMapAttrCachedWTRA|force_shared; break; sl@0: case RCacheTestDevice::E_InnerWBRA: info.iActualMapAttr |= EMapAttrCachedWBRA|force_shared; break; sl@0: case RCacheTestDevice::E_InnerWB: info.iActualMapAttr |= EMapAttrCachedWBWA|force_shared; break; sl@0: sl@0: case RCacheTestDevice::E_OuterWT: info.iActualMapAttr |= EMapAttrL2CachedWTRA; break; sl@0: case RCacheTestDevice::E_OuterWBRA: info.iActualMapAttr |= EMapAttrL2CachedWBRA; break; sl@0: case RCacheTestDevice::E_OuterWB: info.iActualMapAttr |= EMapAttrL2CachedWBWA; break; sl@0: sl@0: case RCacheTestDevice::E_InOutWT: info.iActualMapAttr |= EMapAttrCachedWTRA|EMapAttrL2CachedWTRA|force_shared; break; sl@0: case RCacheTestDevice::E_InOutWBRA: info.iActualMapAttr |= EMapAttrCachedWBRA|EMapAttrL2CachedWBRA|force_shared; break; sl@0: case RCacheTestDevice::E_InOutWB: info.iActualMapAttr |= EMapAttrCachedWBWA|EMapAttrL2CachedWBWA|force_shared; break; sl@0: sl@0: case RCacheTestDevice::E_StronglyOrder: sl@0: new (&info.iActualMapAttr) TMappingAttributes2(EMemAttStronglyOrdered,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Device: sl@0: new (&info.iActualMapAttr) TMappingAttributes2(EMemAttDevice,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Normal_Uncached: sl@0: new (&info.iActualMapAttr) TMappingAttributes2(EMemAttNormalUncached,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Normal_Cached: sl@0: new (&info.iActualMapAttr) TMappingAttributes2(EMemAttNormalCached,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse); sl@0: break; sl@0: sl@0: #if defined(__CPU_MEMORY_TYPE_REMAPPING) sl@0: case RCacheTestDevice::E_InnerWT_Remapped: sl@0: case RCacheTestDevice::E_InnerWBRA_Remapped: sl@0: case RCacheTestDevice::E_InnerWB_Remapped: sl@0: case RCacheTestDevice::E_InOutWT_Remapped: sl@0: case RCacheTestDevice::E_InOutWBRA_Remapped: sl@0: case RCacheTestDevice::E_InOutWB_Remapped: sl@0: #ifdef __SMP__ sl@0: info.iShared = ETrue; sl@0: #endif sl@0: case RCacheTestDevice::E_OuterWT_Remapped: sl@0: case RCacheTestDevice::E_OuterWBRA_Remapped: sl@0: case RCacheTestDevice::E_OuterWB_Remapped: sl@0: Remap(info.iCacheAttr); sl@0: new (&info.iActualMapAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse); sl@0: break; sl@0: #endif sl@0: sl@0: case RCacheTestDevice::E_Default: sl@0: { sl@0: // Run the test against test function from rom image (no need for extra memory chunks) sl@0: if (info.iSize > TestCodeFuncSize()) sl@0: return KErrNoMemory; // TestCodeFunc is not big enough to conduct the test. sl@0: sl@0: TInt startAddr = (TInt)TestCodeFunc + TestCodeFuncSize() - info.iSize; sl@0: sl@0: // This will invalidate (aka purge) test function from L2 cache. sl@0: Cache::SyncMemoryAfterDmaRead((TLinAddr)startAddr, info.iSize); sl@0: sl@0: // Execute the test sl@0: time = NKern::TickCount(); sl@0: LoopTestCodeFunc((CodeTest*)startAddr); sl@0: info.iTime = NKern::TickCount() - time; sl@0: sl@0: info.iActualMapAttr = 0; //Not relevant. sl@0: kumemput(a1,&info,sizeof(info)); sl@0: return KErrNone; sl@0: } sl@0: default: sl@0: return KErrArgument; sl@0: } sl@0: sl@0: // Run the test against test function from memory chunk with cache attributes as specified in info.iCacheState. sl@0: // As we need a chunk with eXecutable permission attribute, can't use shared chunk. Take HwChunk instead. sl@0: DPlatChunkHw* chunk; sl@0: TPhysAddr physBase; // This will be base physical address of the chunk sl@0: TLinAddr linearBase; // This will be base linear address of the chunk sl@0: NKern::ThreadEnterCS(); sl@0: r = Epoc::AllocPhysicalRam(Kern::RoundToPageSize(info.iSize), physBase, 0);//Allocate RAM. This will set aPhysAddr sl@0: if (r) sl@0: { sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: r = DPlatChunkHw::New (chunk, physBase, Kern::RoundToPageSize(info.iSize), info.iActualMapAttr);//Create chunk sl@0: if (r) sl@0: { sl@0: Epoc::FreePhysicalRam(physBase, Kern::RoundToPageSize(info.iSize)); sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: linearBase = chunk->LinearAddress(); sl@0: sl@0: // Create nop,nop,...,nop,ret sequence at the start of the chunk with size = info.iSize sl@0: TInt nopInstr = ((TInt*)TestCodeFunc)[0]; // NOP is the first instruction from TestCodeFunc sl@0: TInt retInstr = ((TInt*)TestCodeFunc)[TestCodeFuncSize()/4-1]; // RET is the last instruction in TestCodeFunc sl@0: for (TInt i = 0; i < (info.iSize/4-1) ; i++) // Put all NOPs... sl@0: ((TInt*)linearBase)[i] = nopInstr; // ... sl@0: ((TInt*)linearBase)[info.iSize/4-1] = retInstr; // ... and add RET at the end. sl@0: sl@0: Cache::IMB_Range((TLinAddr)linearBase, info.iSize); // Sync L1 Instruction & Data cache sl@0: //Fluch the memory from which the test funcion executes. This will give fair chance to all test cases. sl@0: Cache::SyncMemoryBeforeDmaWrite(linearBase, info.iSize); // This will clean L1&L2 cache. sl@0: Cache::SyncMemoryAfterDmaRead(linearBase, info.iSize); // This will invalidate (aka purge) L1&L2 cache. sl@0: sl@0: // Execute the test sl@0: time = NKern::TickCount(); sl@0: LoopTestCodeFunc((CodeTest*)linearBase); sl@0: info.iTime = NKern::TickCount() - time; sl@0: sl@0: kumemput(a1,&info,sizeof(info)); sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: chunk->Close(NULL); sl@0: Epoc::FreePhysicalRam(physBase, Kern::RoundToPageSize(info.iSize)); sl@0: NKern::ThreadLeaveCS(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Tests WriteBack mode: sl@0: (1)Writes down data into BW cached memory. sl@0: (2)Purge the cache. sl@0: (3)Counts the bytes that reach the main memory. sl@0: @param aWriteAlloc True if WriteAllocate to test, EFalse if ReadAllocate sl@0: */ sl@0: TInt DCacheTest::TestWriteBackMode(TAny* a1, TBool aWriteAlloc) sl@0: { sl@0: TInt r, cacheAttr = EMapAttrSupRw; sl@0: TUint i, counter = 0; sl@0: const TInt pattern = 0xabcdef12; sl@0: sl@0: RCacheTestDevice::TChunkTest info; sl@0: kumemget(&info,a1,sizeof(info)); sl@0: #ifdef __SMP__ sl@0: TUint32 force_shared = EMapAttrShared; sl@0: #else sl@0: TUint32 force_shared = 0; sl@0: #endif sl@0: sl@0: switch (info.iCacheAttr) sl@0: { sl@0: #if defined(__CPU_MEMORY_TYPE_REMAPPING) sl@0: case RCacheTestDevice::E_InnerWBRA_Remapped: sl@0: case RCacheTestDevice::E_InnerWB_Remapped: sl@0: case RCacheTestDevice::E_OuterWBRA_Remapped: sl@0: case RCacheTestDevice::E_OuterWB_Remapped: sl@0: Remap(info.iCacheAttr); sl@0: new (&cacheAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,ETrue,force_shared); sl@0: break; sl@0: #endif sl@0: case RCacheTestDevice::E_InnerWBRA: cacheAttr |= EMapAttrCachedWBRA|force_shared; break; sl@0: case RCacheTestDevice::E_InnerWB: cacheAttr |= EMapAttrCachedWBWA|force_shared; break; sl@0: case RCacheTestDevice::E_OuterWBRA: cacheAttr |= EMapAttrL2CachedWBRA|force_shared; break; sl@0: case RCacheTestDevice::E_OuterWB: cacheAttr |= EMapAttrL2CachedWBWA|force_shared; break; sl@0: default: return KErrArgument; sl@0: } sl@0: // Create chunk sl@0: if (KErrNone!=(r=AllocPhysicalRam(info.iSize))) return r; sl@0: if (KErrNone!=(r=CreateSharedChunk(cacheAttr, info.iActualMapAttr))) return r; sl@0: sl@0: for (i=0; i<(iSize>>2) ; i++) ((TInt*)iChunkBase)[i] = 0; //Zero-fill cache and... sl@0: Cache::SyncMemoryBeforeDmaWrite(iChunkBase, iSize); //... clean the cache down to memory sl@0: sl@0: Cache::SyncMemoryAfterDmaRead(iChunkBase, iSize); //Invalidate (aka purge). sl@0: sl@0: // Fill in cached region with the pattern. sl@0: for (i=0; i<(iSize>>2); i++) sl@0: { sl@0: if (!aWriteAlloc) iDummy = ((TInt*)iChunkBase)[i]; // Don't read if WriteAllocate is tested sl@0: ((TInt*)iChunkBase)[i] = pattern; sl@0: } sl@0: sl@0: Cache::SyncMemoryAfterDmaRead(iChunkBase, iSize); //Invalidate (aka purge) cache. Data in cache should be destroyed sl@0: CloseSharedChunk(); // Close cached chunk. sl@0: sl@0: //Create non-cached chunk over the same physical memory sl@0: if (KErrNone!=(r=CreateSharedChunk(EMapAttrSupRw , iDummy))) return r; sl@0: sl@0: // Counts out how many bytes have reached RAM sl@0: for (i=0; i<(iSize>>2); i++) if (((TInt*)iChunkBase)[i] == pattern) counter++; sl@0: sl@0: info.iSize = counter<<2; //Return the number of bytes that reached the main memory sl@0: CloseSharedChunk(); sl@0: FreePhysicalRam(); sl@0: sl@0: kumemput(a1,&info,sizeof(info)); sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Exercises SyncMemoryBeforeDmaWrite & SyncMemoryAfterDmaRead (that call L1/L2 Cache Clean & Purge methods) sl@0: This just ensures that they do not panic (doesn't do any functional test). sl@0: */ sl@0: TInt DCacheTest::TestL2Maintenance() sl@0: { sl@0: // Create 20000h big chunk with the the memory commited as: sl@0: // |0| NotCommited |64K| Commited |128K| NotCommited |192K| Commited |256K| sl@0: #ifdef __SMP__ sl@0: TUint32 force_shared = EMapAttrShared; sl@0: #else sl@0: TUint32 force_shared = 0; sl@0: #endif sl@0: TInt r; sl@0: TChunkCreateInfo info; sl@0: info.iType = TChunkCreateInfo::ESharedKernelSingle; sl@0: info.iMaxSize = 0x40000; sl@0: info.iMapAttr = EMapAttrSupRw | EMapAttrCachedWBWA | EMapAttrL2CachedWBWA | force_shared; sl@0: info.iOwnsMemory = ETrue; // Use memory from system's free pool sl@0: info.iDestroyedDfc = NULL; sl@0: sl@0: TLinAddr chunkAddr; sl@0: TUint32 mapAttr; sl@0: DChunk* chunk; sl@0: TInt pageSize = 0x1000; //4K sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: if (KErrNone != (r = Kern::ChunkCreate(info, chunk, chunkAddr, mapAttr))) sl@0: { sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: r = Kern::ChunkCommit(chunk,0x10000,0x10000); sl@0: if(r!=KErrNone) sl@0: { sl@0: Kern::ChunkClose(chunk); sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: r = Kern::ChunkCommit(chunk,0x30000,0x10000); sl@0: if(r!=KErrNone) sl@0: { sl@0: Kern::ChunkClose(chunk); sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: TInt valid = chunkAddr+0x10000; sl@0: sl@0: #if defined(__ARM_L220_CACHE__) || defined(__ARM_L210_CACHE__) sl@0: // Check L2 cache maintenance for invalid addresses. sl@0: // On ARMv6, clean/purge L1 cache of the region with invalid addresses panics. sl@0: // However, cleaning/purging a large region above the threshold will clean/purge entire L1 cache(which doesn't panic). sl@0: // That is why the following calls run against 256KB. sl@0: //We cannot do that on XScale L2 cache as it would generate page walk data abort. sl@0: TInt invalid = chunkAddr; sl@0: Cache::SyncMemoryBeforeDmaWrite(invalid+20, 0x40000-20); sl@0: Cache::SyncMemoryAfterDmaRead(invalid+100,0x40000-101); sl@0: #endif sl@0: sl@0: sl@0: // The following calls operate against valid memory regions. sl@0: Cache::SyncMemoryAfterDmaRead(valid+1, 0); sl@0: Cache::SyncMemoryAfterDmaRead(valid+32, 12); sl@0: Cache::SyncMemoryAfterDmaRead(valid+1, 0); sl@0: Cache::SyncMemoryBeforeDmaWrite(valid+2, 1); sl@0: Cache::SyncMemoryAfterDmaRead(valid+3, 2); sl@0: Cache::SyncMemoryBeforeDmaWrite(valid+4, 3); sl@0: Cache::SyncMemoryAfterDmaRead(valid+5, 4); sl@0: Cache::SyncMemoryBeforeDmaWrite(valid+6, 5); sl@0: Cache::SyncMemoryAfterDmaRead(valid+7, 6); sl@0: Cache::SyncMemoryBeforeDmaWrite(valid+8, 7); sl@0: Cache::SyncMemoryAfterDmaRead(valid+9, 8); sl@0: Cache::SyncMemoryBeforeDmaWrite(valid+10, 9); sl@0: Cache::SyncMemoryAfterDmaRead(valid+11, 10); sl@0: Cache::SyncMemoryBeforeDmaWrite(valid+12, 11); sl@0: Cache::SyncMemoryAfterDmaRead(valid+13, 12); sl@0: Cache::SyncMemoryBeforeDmaWrite(valid+14, 13); sl@0: Cache::SyncMemoryAfterDmaRead(valid+15, 14); sl@0: sl@0: TLinAddr page = (valid+2*pageSize); sl@0: Cache::SyncMemoryBeforeDmaWrite(page, 0); sl@0: Cache::SyncMemoryAfterDmaRead(page, 0); sl@0: Cache::SyncMemoryBeforeDmaWrite(page-1, 2); sl@0: Cache::SyncMemoryAfterDmaRead(page-2, 4); sl@0: Cache::SyncMemoryBeforeDmaWrite(page-3, 6); sl@0: Cache::SyncMemoryAfterDmaRead(page-4, 8); sl@0: Cache::SyncMemoryBeforeDmaWrite(page-5, 10); sl@0: Cache::SyncMemoryAfterDmaRead(page-6, 12); sl@0: sl@0: Cache::SyncMemoryBeforeDmaWrite(page, 2*pageSize); sl@0: Cache::SyncMemoryAfterDmaRead(page-1, 2*pageSize); sl@0: Cache::SyncMemoryBeforeDmaWrite(page+1, 2*pageSize); sl@0: Cache::SyncMemoryAfterDmaRead(page+3, 2*pageSize); sl@0: Cache::SyncMemoryBeforeDmaWrite(page-3, 2*pageSize); sl@0: sl@0: Cache::SyncMemoryBeforeDmaWrite(valid, 64, EMapAttrCachedMax); sl@0: Cache::SyncMemoryBeforeDmaRead(valid, 64, EMapAttrCachedMax); sl@0: Cache::SyncMemoryAfterDmaRead(valid, 64, EMapAttrCachedMax); sl@0: sl@0: sl@0: Cache::IMB_Range(0, 0xffffffff);//will cause: Clean all DCache & Purge all ICache sl@0: // Close the chunk sl@0: NKern::ThreadEnterCS(); sl@0: Kern::ChunkClose(chunk); sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: sl@0: //Check maintenance functions against entire cache (we need memory region >=8*cache size) sl@0: info.iType = TChunkCreateInfo::ESharedKernelSingle; sl@0: info.iMaxSize = 0x100000; //1MB will do sl@0: info.iMapAttr = EMapAttrSupRw | EMapAttrCachedWBWA | EMapAttrL2CachedWBWA | force_shared; sl@0: info.iOwnsMemory = ETrue; // Use memory from system's free pool sl@0: info.iDestroyedDfc = NULL; sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: if (KErrNone != (r = Kern::ChunkCreate(info, chunk, chunkAddr, mapAttr))) sl@0: { sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: r = Kern::ChunkCommit(chunk,0x0,0x100000); sl@0: if(r!=KErrNone) sl@0: { sl@0: Kern::ChunkClose(chunk); sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: Cache::SyncMemoryBeforeDmaWrite(chunkAddr, 0x100000); sl@0: Cache::SyncMemoryAfterDmaRead(chunkAddr, 0x100000); sl@0: sl@0: // Close the chunk sl@0: NKern::ThreadEnterCS(); sl@0: Kern::ChunkClose(chunk); sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DCacheTest::TestUseCase(TAny* a1) sl@0: { sl@0: TInt r = KErrNone; sl@0: TInt time; sl@0: sl@0: RCacheTestDevice::TChunkTest info; sl@0: kumemget(&info,a1,sizeof(info)); sl@0: sl@0: TUint32 chunkAttr = EMapAttrSupRw; sl@0: #ifdef __SMP__ sl@0: TUint32 force_shared = EMapAttrShared; sl@0: #else sl@0: TUint32 force_shared = 0; sl@0: #endif sl@0: if (info.iShared) chunkAttr |= EMapAttrShared; sl@0: sl@0: switch (info.iCacheAttr) sl@0: { sl@0: case RCacheTestDevice::E_StronglyOrder: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttStronglyOrdered,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Device: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttDevice,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Normal_Uncached: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttNormalUncached,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse); sl@0: break; sl@0: case RCacheTestDevice::E_Normal_Cached: sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttNormalCached,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse); sl@0: break; sl@0: #if defined(__CPU_MEMORY_TYPE_REMAPPING) sl@0: case RCacheTestDevice::E_InOutWT_Remapped: sl@0: Remap(info.iCacheAttr); sl@0: new (&chunkAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,EFalse,(info.iShared|force_shared)?ETrue:EFalse); sl@0: #else sl@0: case RCacheTestDevice::E_InOutWT: chunkAttr |= EMapAttrCachedWTRA|EMapAttrL2CachedWTRA|force_shared; sl@0: #endif sl@0: break; sl@0: default: sl@0: return KErrArgument; sl@0: } sl@0: sl@0: // Create chunk sl@0: if (KErrNone!=(r=AllocPhysicalRam(Kern::RoundToPageSize(info.iSize)))) return r; sl@0: if (KErrNone!=(r=CreateSharedChunk(chunkAttr, info.iActualMapAttr))) return r; sl@0: sl@0: //Alloc from the heap sl@0: NKern::ThreadEnterCS(); sl@0: iHeap1 = (TInt*)Kern::Alloc(Max(info.iSize,0x8000)); sl@0: if (iHeap1==NULL) {NKern::ThreadLeaveCS();return KErrNoMemory;} sl@0: iHeap2 = (TInt*)Kern::Alloc(0x8000); sl@0: if (iHeap2==NULL) {Kern::Free((TAny*)iHeap1);NKern::ThreadLeaveCS();return KErrNoMemory;} sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: Cache::SyncMemoryAfterDmaRead(iChunkBase, info.iSize); // Invalidate (aka purge) cache. sl@0: time = NKern::TickCount(); sl@0: switch(info.iUseCase) sl@0: { sl@0: case 0: r = UseCase_ReadFromChunk(info);break; sl@0: case 1: r = UseCase_ReadFromChunk_ReadFromHeap(info);break; sl@0: case 2: r = UseCase_WriteToChunk(info);break; sl@0: case 3: r = UseCase_WriteToChunk_ReadFromHeap(info);break; sl@0: default: r = KErrArgument; sl@0: } sl@0: info.iTime = NKern::TickCount() - time; sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: Kern::Free((TAny*)iHeap1); sl@0: Kern::Free((TAny*)iHeap2); sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: CloseSharedChunk(); sl@0: FreePhysicalRam(); sl@0: sl@0: kumemput(a1,&info,sizeof(info)); sl@0: return r; sl@0: } sl@0: sl@0: TInt DCacheTest::UseCase_ReadFromChunk(RCacheTestDevice::TChunkTest& info) sl@0: { sl@0: TInt i; sl@0: for (i=0; i< info.iLoops; i++) sl@0: { sl@0: //Simulate - evict the chunk from the cache) sl@0: Cache::SyncMemoryBeforeDmaRead(iChunkBase, info.iSize, info.iActualMapAttr); // Invalidate (aka purge) cache. sl@0: sl@0: //Read DMA data sl@0: memcpy((TAny*)iHeap1, (const TAny*)iChunkBase, info.iSize); sl@0: //for (j=0; j < info.iSize>>2; j++) iDummy = *((TInt*)iChunkBase+j); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DCacheTest::UseCase_ReadFromChunk_ReadFromHeap(RCacheTestDevice::TChunkTest& info) sl@0: { sl@0: TInt i; sl@0: for (i=0; i< info.iLoops; i++) sl@0: { sl@0: //Simulate - evict the chunk memory from the cache sl@0: Cache::SyncMemoryBeforeDmaRead(iChunkBase, info.iSize, info.iActualMapAttr); // Invalidate (aka purge) cache. sl@0: sl@0: //Read DMA memory sl@0: memcpy((TAny*)iHeap1, (const TAny*)iChunkBase, info.iSize); sl@0: sl@0: //Simulate Kernel activities - reading heap2 sl@0: memcpy((TAny*)iHeap1, (const TAny*)iHeap2, 0x8000); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DCacheTest::UseCase_WriteToChunk(RCacheTestDevice::TChunkTest& info) sl@0: { sl@0: TInt i; sl@0: for (i=0; i< info.iLoops; i++) sl@0: { sl@0: //Simulate - evict the chunk memory from the cache sl@0: Cache::SyncMemoryBeforeDmaRead(iChunkBase, info.iSize, info.iActualMapAttr); // Invalidate (aka purge) cache. sl@0: sl@0: //Write DMA memory sl@0: memcpy((TAny*)iChunkBase, (const TAny*)iHeap1, info.iSize); sl@0: Cache::SyncMemoryBeforeDmaWrite(iChunkBase, info.iSize, info.iActualMapAttr); // Clean cache. sl@0: sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DCacheTest::UseCase_WriteToChunk_ReadFromHeap(RCacheTestDevice::TChunkTest& info) sl@0: { sl@0: TInt i; sl@0: for (i=0; i< info.iLoops; i++) sl@0: { sl@0: //Simulate - evict the chunk memory from the cache sl@0: Cache::SyncMemoryBeforeDmaRead(iChunkBase, info.iSize, info.iActualMapAttr); // Invalidate (aka purge) cache. sl@0: sl@0: //Write DMA memory sl@0: memcpy((TAny*)iChunkBase, (const TAny*)iHeap1, info.iSize); sl@0: Cache::SyncMemoryBeforeDmaWrite(iChunkBase, info.iSize, info.iActualMapAttr); // Clean cache. sl@0: sl@0: //Simulate Kernel activities - reading heap2 sl@0: memcpy((TAny*)iHeap1, (const TAny*)iHeap2, 0x8000); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: // Entry point sl@0: TInt DCacheTest::Request(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: TInt r = KErrNone; sl@0: #ifdef __SMP__ sl@0: TUint32 affinity = NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), 0); sl@0: #endif sl@0: switch (aFunction) sl@0: { sl@0: case RCacheTestDevice::EGetCacheInfo: r = GetCacheInfo(a1); break; sl@0: case RCacheTestDevice::ETestDataChunk: r = TestDataChunk(a1); break; sl@0: case RCacheTestDevice::ETestCodeChunk: r = TestCodeChunk(a1); break; sl@0: case RCacheTestDevice::ETestWriteBackReadAllocate: r = TestWriteBackMode(a1, EFalse); break; sl@0: case RCacheTestDevice::ETestWriteBackWriteAllocate: r = TestWriteBackMode(a1, ETrue); break; sl@0: case RCacheTestDevice::ETesL2Maintenance: r = TestL2Maintenance(); break; sl@0: case RCacheTestDevice::EGetThreshold: r = GetThreshold(a1); break; sl@0: case RCacheTestDevice::ESetThreshold: r = SetThreshold(a1); break; sl@0: case RCacheTestDevice::ETestUseCase: r = TestUseCase(a1); break; sl@0: default: r=KErrNotSupported; sl@0: } sl@0: #ifdef __SMP__ sl@0: NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), affinity); sl@0: #endif sl@0: return r; sl@0: } sl@0: sl@0: ////////////////////////////////////////// sl@0: class DTestFactory : public DLogicalDevice sl@0: { sl@0: public: sl@0: DTestFactory(); 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: DTestFactory::DTestFactory() sl@0: { sl@0: iParseMask = KDeviceAllowUnit; sl@0: iUnitsMask = 0x3; sl@0: } sl@0: sl@0: TInt DTestFactory::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: CacheTestDriver = new DCacheTest; sl@0: aChannel = CacheTestDriver; sl@0: return (aChannel ? KErrNone : KErrNoMemory); sl@0: } sl@0: sl@0: TInt DTestFactory::Install() sl@0: { sl@0: return SetName(&KCacheTestDriverName); sl@0: } sl@0: sl@0: void DTestFactory::GetCaps(TDes8& /*aDes*/) const sl@0: { sl@0: } sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DTestFactory; sl@0: }