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