kerneltest/e32test/power/d_frqchg.cpp
changeset 201 43365a9b78a3
equal deleted inserted replaced
200:73ea206103e6 201:43365a9b78a3
       
     1 // Copyright (c) 2010-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\power\d_frqchg.cpp
       
    15 // LDD for testing frequency changing
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <kernel/kernel.h>
       
    20 #include "d_frqchg.h"
       
    21 
       
    22 #if defined(__EPOC32__) && defined(__SMP__) && defined(__MARM__)
       
    23 #define __SUPPORT_LOCAL_TIMER_PRESCALE__
       
    24 
       
    25 #include <nk_priv.h>
       
    26 #include <arm_tmr.h>
       
    27 #endif
       
    28 
       
    29 
       
    30 #ifdef __PLATFORM_SUPPORTS_DVFS__
       
    31 /**
       
    32   Baseport needs to supply this function to disable DVFS whilst test is running. 
       
    33   The test relies on changing prescalers in local and global timer directly rather than
       
    34   actually changing frequency. Consequently DVFS must be disabled when the test is running
       
    35 
       
    36   This function when driver is loaded. 
       
    37   @return KErrNone if succesful
       
    38  */
       
    39 extern TInt DisableDvfs();
       
    40 
       
    41 /**
       
    42    if plaftorm supports DVFS this function will be called when the driver is unloaded
       
    43  */
       
    44 extern void RestoreDvfs();
       
    45 #endif
       
    46 
       
    47 
       
    48 
       
    49 #if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__)
       
    50 TInt Multiply(SRatio& aDest, const SRatio& aSrc)
       
    51 	{
       
    52 	TUint64 x = aDest.iM;
       
    53 	TUint64 y = aSrc.iM;
       
    54 	x *= y;
       
    55 	if (x==0)
       
    56 		{
       
    57 		aDest.iM = 0;
       
    58 		aDest.iX = 0;
       
    59 		return KErrNone;
       
    60 		}
       
    61 	TInt exp = aDest.iX + aSrc.iX + 32;
       
    62 	if (TInt64(x) >= 0)
       
    63 		x<<=1, --exp;
       
    64 	aDest.iM = I64HIGH(x);
       
    65 	if (I64LOW(x) & 0x80000000u)
       
    66 		{
       
    67 		if (++aDest.iM == 0)
       
    68 			aDest.iM = 0x80000000u, ++exp;
       
    69 		}
       
    70 	if (exp > 32767)
       
    71 		{
       
    72 		aDest.iM = 0xffffffffu;
       
    73 		aDest.iX = 32767;
       
    74 		return KErrOverflow;
       
    75 		}
       
    76 	if (exp < -32768)
       
    77 		{
       
    78 		aDest.iM = 0;
       
    79 		aDest.iX = 0;
       
    80 		return KErrUnderflow;
       
    81 		}
       
    82 	aDest.iX = (TInt16)exp;
       
    83 	return KErrNone;
       
    84 	}
       
    85 
       
    86 // Calculate frequency ratio for specified prescale value
       
    87 // Ratio = (default+1)/(current+1)
       
    88 void PrescaleRatio(SRatio& aR, TInt aDefault, TInt aCurrent)
       
    89 	{
       
    90 	SRatio df;
       
    91 	df.Set(TUint32(aDefault+1));
       
    92 	aR.Set(TUint32(aCurrent+1));
       
    93 	aR.Reciprocal();
       
    94 	Multiply(aR, df);
       
    95 	}
       
    96 #endif
       
    97 
       
    98 class DFrqChgFactory : public DLogicalDevice
       
    99 //
       
   100 // Test LDD factory
       
   101 //
       
   102 	{
       
   103 public:
       
   104 	DFrqChgFactory();
       
   105 	virtual ~DFrqChgFactory();
       
   106 	virtual TInt Install(); 					//overriding pure virtual
       
   107 	virtual void GetCaps(TDes8& aDes) const;	//overriding pure virtual
       
   108 	virtual TInt Create(DLogicalChannelBase*& aChannel); 	//overriding pure virtual
       
   109 	};
       
   110 
       
   111 class DFrqChg : public DLogicalChannelBase
       
   112 //
       
   113 // Test logical channel
       
   114 //
       
   115 	{
       
   116 public:
       
   117 	virtual ~DFrqChg();
       
   118 protected:
       
   119 	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
       
   120 	virtual TInt Request(TInt aReqNo, TAny* a1, TAny* a2);
       
   121 #if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__)
       
   122 	void PopulateDefaultPrescaleList();
       
   123 	void SetLocalTimerPrescaler(TUint32 aCpus, TInt aPrescale);
       
   124 	TScheduler* iS;
       
   125 	TInt iDefaultPrescale[KMaxCpus];
       
   126 #if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__)
       
   127 	void SetGlobalTimerPrescaler(TInt aPrescale);
       
   128 	TInt iDefaultGTPrescale;
       
   129 #endif
       
   130 #endif
       
   131 
       
   132 	};
       
   133 
       
   134 
       
   135 
       
   136 DECLARE_STANDARD_LDD()
       
   137 	{
       
   138 	return new DFrqChgFactory;
       
   139 	}
       
   140 
       
   141 //
       
   142 // Constructor
       
   143 //
       
   144 DFrqChgFactory::DFrqChgFactory()
       
   145 	{
       
   146 	}
       
   147 
       
   148 //
       
   149 // Destructor, called on unload
       
   150 //
       
   151 DFrqChgFactory::~DFrqChgFactory()
       
   152 	{
       
   153 #ifdef __PLATFORM_SUPPORTS_DVFS__
       
   154 	RestoreDvfs();
       
   155 #endif
       
   156 	}
       
   157 
       
   158 
       
   159 
       
   160 //
       
   161 // Create new channel
       
   162 //
       
   163 TInt DFrqChgFactory::Create(DLogicalChannelBase*& aChannel)
       
   164 	{
       
   165 	aChannel=new DFrqChg;
       
   166 	return aChannel?KErrNone:KErrNoMemory;
       
   167 	}
       
   168 
       
   169 
       
   170 //
       
   171 // Install the LDD - overriding pure virtual
       
   172 //
       
   173 TInt DFrqChgFactory::Install()
       
   174 	{
       
   175 #ifdef __PLATFORM_SUPPORTS_DVFS__
       
   176 	TInt r = DisableDvfs();
       
   177 	if (KErrNone != r) return r;
       
   178 #endif
       
   179 	return SetName(&KLddName);
       
   180 	}
       
   181 
       
   182 
       
   183 //
       
   184 // Get capabilities - overriding pure virtual
       
   185 //
       
   186 void DFrqChgFactory::GetCaps(TDes8& /*aDes*/) const
       
   187 	{
       
   188 	}
       
   189 
       
   190 
       
   191 //
       
   192 // Create channel
       
   193 //
       
   194 TInt DFrqChg::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
       
   195 	{
       
   196 #if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__)
       
   197 	iS = (TScheduler*)TScheduler::Ptr();
       
   198 	PopulateDefaultPrescaleList();
       
   199 #endif
       
   200 	return KErrNone;
       
   201 	}
       
   202 
       
   203 
       
   204 //
       
   205 // Destructor
       
   206 //
       
   207 DFrqChg::~DFrqChg()
       
   208 	{
       
   209 #if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__)
       
   210 	// restore prescalers
       
   211 	SetLocalTimerPrescaler((TUint32) -1, -1);
       
   212 #if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__)
       
   213 	SetGlobalTimerPrescaler(-1);
       
   214 #endif
       
   215 #endif
       
   216 	}
       
   217 
       
   218 
       
   219 TInt DFrqChg::Request(TInt aReqNo, TAny* a1, TAny* a2)
       
   220 	{
       
   221 	SRatioInv ri;
       
   222 	TInt r = KErrNone;
       
   223 	switch (aReqNo)
       
   224 		{
       
   225 		case RFrqChg::EControl_RatioSet:
       
   226 			{
       
   227 			kumemget32(&ri.iR, a1, sizeof(SRatio));
       
   228 			ri.iR.Set(ri.iR.iM, (TUint32)a2);
       
   229 			kumemput32(a1, &ri.iR, sizeof(SRatio));
       
   230 			break;
       
   231 			}
       
   232 		case RFrqChg::EControl_RatioReciprocal:
       
   233 			{
       
   234 			kumemget32(&ri.iR, a1, sizeof(SRatio));
       
   235 			r = ri.iR.Reciprocal();
       
   236 			kumemput32(a1, &ri.iR, sizeof(SRatio));
       
   237 			break;
       
   238 			}
       
   239 		case RFrqChg::EControl_RatioMult:
       
   240 			{
       
   241 			kumemget32(&ri.iR, a1, sizeof(SRatio));
       
   242 			kumemget32(&ri.iI.iM, a2, sizeof(TUint32));
       
   243 			r = ri.iR.Mult(ri.iI.iM);
       
   244 			kumemput32(a2, &ri.iI.iM, sizeof(TUint32));
       
   245 			break;
       
   246 			}
       
   247 		case RFrqChg::EControl_RatioInvSet:
       
   248 			{
       
   249 			SRatio ratio;
       
   250 			const SRatio* p = 0;
       
   251 			if (a2)
       
   252 				{
       
   253 				kumemget32(&ratio, a2, sizeof(SRatio));
       
   254 				p = &ratio;
       
   255 				}
       
   256 			ri.Set(p);
       
   257 			kumemput32(a1, &ri, sizeof(SRatioInv));
       
   258 			break;
       
   259 			}
       
   260 #if defined(__EPOC32__) && defined(__SMP__) && defined(__MARM__)
       
   261 		case RFrqChg::EControl_FrqChgTestPresent:
       
   262 			break;
       
   263 		case RFrqChg::EControl_SetCurrentThreadPriority:
       
   264 			NKern::ThreadSetPriority(NKern::CurrentThread(), (TInt)a1);
       
   265 			break;
       
   266 		case RFrqChg::EControl_SetCurrentThreadCpu:
       
   267 			{
       
   268 			TUint32 old = 0;
       
   269 			old =  NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), (TUint32)a1);
       
   270 			if (a2) 
       
   271 				{
       
   272 				kumemput32(a2, &old, sizeof(TUint32));
       
   273 				}
       
   274 			
       
   275 			old =  NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), (TUint32)a1);
       
   276 			}
       
   277 			
       
   278 			break;
       
   279 		case RFrqChg::EControl_SetCurrentThreadTimeslice:
       
   280 			{
       
   281 			TInt ts = NKern::TimesliceTicks((TUint32)a1);
       
   282 			NKern::ThreadSetTimeslice(NKern::CurrentThread(), ts);
       
   283 			NKern::YieldTimeslice();
       
   284 			break;
       
   285 			}
       
   286 #endif
       
   287 #if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__)
       
   288 		case RFrqChg::EControl_SetLocalTimerPrescaler:
       
   289 			{
       
   290 			TUint32 cpus = (TUint32)a1;
       
   291 			TInt prescale = (TInt)a2;
       
   292 			SetLocalTimerPrescaler(cpus, prescale);
       
   293 			break;
       
   294 			}
       
   295 #if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__)
       
   296 	case RFrqChg::EControl_ReadGlobalTimerAndTimestamp:
       
   297 		    {
       
   298 			ArmGlobalTimer* tmr = iS->iSX.iGlobalTimerAddr;
       
   299 			TUint32 highlow[2];
       
   300 			do
       
   301 				{
       
   302 				highlow[1] = tmr->iTimerCountHigh;
       
   303 				highlow[0] = tmr->iTimerCountLow;
       
   304 				} while(highlow[1]!=tmr->iTimerCountHigh);
       
   305 			TUint64 ts = NKern::Timestamp();
       
   306 			kumemput32(a1,&highlow[0],sizeof(TUint64));
       
   307 			kumemput32(a2,&ts,sizeof(TUint64));
       
   308 			break;
       
   309 		 }
       
   310 	case RFrqChg::EControl_SetGlobalTimerPrescaler:
       
   311 		    {
       
   312 			SetGlobalTimerPrescaler((TInt)a1);
       
   313 			break;
       
   314 		 }
       
   315 #endif
       
   316 #endif
       
   317 		default:
       
   318 			r = KErrNotSupported;
       
   319 			break;
       
   320 		}
       
   321 	return r;
       
   322 	}
       
   323 
       
   324 
       
   325 #if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__)
       
   326 void DFrqChg::PopulateDefaultPrescaleList()
       
   327 	{
       
   328 	TInt nc = NKern::NumberOfCpus();
       
   329 	NThread* nt = NKern::CurrentThread();
       
   330 	TUint32 aff0 = NKern::ThreadSetCpuAffinity(nt, 0);
       
   331 	TInt i;
       
   332 	for (i=0; i<nc; ++i)
       
   333 		{
       
   334 		NKern::ThreadSetCpuAffinity(nt, i);
       
   335 		ArmLocalTimer* tmr = (ArmLocalTimer*)iS->iSX.iLocalTimerAddr;
       
   336 		TInt pv = (tmr->iTimerCtrl & E_ArmTmrCtrl_PrescaleMask) >> E_ArmTmrCtrl_PrescaleShift;
       
   337 		iDefaultPrescale[i] = pv;
       
   338 		}
       
   339 	NKern::ThreadSetCpuAffinity(nt, aff0);
       
   340 #if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__)
       
   341 	ArmGlobalTimer* tmr = iS->iSX.iGlobalTimerAddr;
       
   342 	TInt pv = (tmr->iTimerCtrl & E_ArmGTmrCtrl_PrescaleMask) >> E_ArmGTmrCtrl_PrescaleShift;
       
   343 	iDefaultGTPrescale = pv;
       
   344 #endif
       
   345 	}
       
   346 
       
   347 void DFrqChg::SetLocalTimerPrescaler(TUint32 aCpus, TInt aPrescale)
       
   348 	{
       
   349 	TInt nc = NKern::NumberOfCpus();
       
   350 	NThread* nt = NKern::CurrentThread();
       
   351 	TUint32 aff0 = NKern::ThreadSetCpuAffinity(nt, 0);
       
   352 	TInt i;
       
   353 	for (i=0; i<nc; ++i)
       
   354 		{
       
   355 		NKern::ThreadSetCpuAffinity(nt, i);
       
   356 		}
       
   357 	for (i=0; i<nc; ++i)
       
   358 		{
       
   359 		NKern::ThreadSetCpuAffinity(nt, i);
       
   360 		TInt pv = aPrescale;
       
   361 		if (pv < 0)
       
   362 			pv = iDefaultPrescale[i];
       
   363 		if (aCpus & (1u<<i))
       
   364 			{
       
   365 			TInt irq = NKern::DisableAllInterrupts();
       
   366 			ArmLocalTimer* tmr = (ArmLocalTimer*)iS->iSX.iLocalTimerAddr;
       
   367 			tmr->iTimerCtrl = (tmr->iTimerCtrl &~ E_ArmTmrCtrl_PrescaleMask) | ((pv << E_ArmTmrCtrl_PrescaleShift) & E_ArmTmrCtrl_PrescaleMask);
       
   368 			__e32_io_completion_barrier();
       
   369 			NKern::RestoreInterrupts(irq);
       
   370 			}
       
   371 		}
       
   372 	NKern::ThreadSetCpuAffinity(nt, aff0);
       
   373 	if (aCpus & 0x80000000u)
       
   374 		{
       
   375 		// notify nanokernel of frequency changes
       
   376 		SVariantInterfaceBlock* vib = iS->iVIB;
       
   377 		SRatio ratio[KMaxCpus];
       
   378 		for (i=0; i<nc; ++i)
       
   379 			{
       
   380 			if (aCpus & (1u<<i))
       
   381 				{
       
   382 				if (aPrescale<0)
       
   383 					ratio[i].Set(1);
       
   384 				else
       
   385 					PrescaleRatio(ratio[i], iDefaultPrescale[i], aPrescale);
       
   386 				vib->iTimerFreqR[i] = &ratio[i];
       
   387 				}
       
   388 			}
       
   389 		(*vib->iFrqChgFn)();
       
   390 		}
       
   391 	}
       
   392 
       
   393 #if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__)
       
   394 void DFrqChg::SetGlobalTimerPrescaler(TInt aPrescale)
       
   395 	{
       
   396 	TInt pv = aPrescale;
       
   397 	if (pv <= 0)
       
   398 		pv = iDefaultGTPrescale;
       
   399 
       
   400 	ArmGlobalTimer* tmr = iS->iSX.iGlobalTimerAddr;
       
   401 	// TInt irq = NKern::DisableAllInterrupts(); 
       
   402 	tmr->iTimerCtrl = (tmr->iTimerCtrl &~ E_ArmGTmrCtrl_PrescaleMask) | ((pv << E_ArmGTmrCtrl_PrescaleShift) & E_ArmGTmrCtrl_PrescaleMask);
       
   403 	__e32_io_completion_barrier();
       
   404 	// NKern::RestoreInterrupts(irq);
       
   405 
       
   406 	// notify nanokernel of frequency changes
       
   407 	SVariantInterfaceBlock* vib = iS->iVIB;
       
   408 	SRatio ratio;
       
   409 	
       
   410 	if (aPrescale<=0)
       
   411 		ratio.Set(1);
       
   412 	else
       
   413 		PrescaleRatio(ratio, iDefaultGTPrescale, aPrescale);
       
   414 
       
   415 	vib->iGTimerFreqR = &ratio;
       
   416 	(*vib->iFrqChgFn)();
       
   417 	}
       
   418 
       
   419 #endif
       
   420 #endif
       
   421