kerneltest/e32test/realtime/d_latncy.cpp
changeset 0 a41df078684a
child 31 56f325a607ea
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/realtime/d_latncy.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,565 @@
+// Copyright (c) 1999-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\realtime\d_latncy.cpp
+// 
+//
+
+#include "platform.h"
+
+#if defined(__MEIG__)
+#include <cl7211.h>
+#elif defined(__MAWD__)
+#include <windermere.h>
+#elif defined(__MISA__)
+#include <sa1100.h>
+#elif defined(__MCOT__)
+#include <cotulla.h>
+#elif defined(__MI920__) || defined(__NI1136__)
+#include <integratorap.h>
+//#define FREE_RUNNING_MODE			// runs the millisecond timer in free running mode
+#elif defined(__IS_OMAP1610__)
+#include <omap_timer.h>
+#include <omap_plat.h>
+#elif defined(__IS_OMAP2420__) || defined(__WAKEUP_3430__)
+#include <omap_hw.h>
+#include <shared_instrtimer.h>
+#elif defined(__EPOC32__) && defined(__CPU_X86)
+#include <x86.h>
+#include <x86pc.h>
+#elif defined(__RVEMUBOARD__)
+#include <rvemuboard.h>
+#elif defined(__NE1_TB__)
+#include <upd35001_timer.h>
+#endif
+
+#ifdef __CPU_ARM
+#include <arm.h>
+#endif
+
+#include <kernel/kern_priv.h>		//temporary
+#include "d_latncy.h"
+
+_LIT(KLddName,"Latency");
+_LIT(KThreadName,"LatencyThreadK");
+
+#if defined(__MEIG__)
+const TInt KTickPeriodMs=2;
+const TInt KTicksPerMillisecond=512;
+#elif defined(__MAWD__)
+const TInt KTickPeriodMs=1;
+const TInt KTicksPerMillisecond=512;
+#elif defined(__MISA__) || defined(__MCOT__)
+const TInt KTicksPerMillisecond=3686;
+const TInt KOstTicks=3685;	// not quite 1ms, so it goes in and out of phase with ms timer
+TUint TriggerTime;
+#elif defined(__MI920__) || defined(__NI1136__)
+const TInt KTickPeriodMs=1;
+#if defined(__MI920__) || defined(__NI1136__)
+#ifdef FREE_RUNNING_MODE	
+const TInt KTicksPerMillisecond=1500;
+#else
+const TInt KTicksPerMillisecond=24000;
+#endif
+#endif
+#elif defined(__IS_OMAP1610__)
+const TInt KTickPeriodMs=1;
+TInt KTicksPerMillisecond = TOmapPlat::GetInputClk()/32000;
+#elif defined(__IS_OMAP2420__) || defined(__WAKEUP_3430__)
+const TInt KTickPeriodMs=1;					// defined for compatibility but not used (ignored)
+const TInt KTicksPerMillisecond = 12000; 	// Hard coded (12Mhz)
+#elif defined(__EPOC32__) && defined(__CPU_X86)
+const TInt KTickPeriodMs=1;
+const TInt KTicksPerMillisecond=1193;
+#elif defined(__RVEMUBOARD__)
+const TInt KTickPeriodMs=1;
+const TInt KTicksPerMillisecond=1000;
+#elif defined(__NE1_TB__)
+const TInt KTickPeriodMs=1;
+const TInt KTicksPerMillisecond=66667;
+#endif
+
+#ifdef _DEBUG
+const TInt KFudgeFactor=1;
+#else
+const TInt KFudgeFactor=1;
+#endif
+
+class DDeviceLatency : public DLogicalDevice
+	{
+public:
+	DDeviceLatency();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+class DLatencyPowerHandler : public DPowerHandler
+	{
+public: // from DPOwerHandler
+	void PowerUp();
+	void PowerDown(TPowerState);
+public:
+	DLatencyPowerHandler(DLatency* aChannel);
+public:
+	DLatency* iChannel;
+	};
+
+
+
+inline TUint DLatency::Ticks()
+	{
+#if defined(__MEIG__)
+	return KTicksPerMillisecond-(*(volatile TUint*)(KEigerTimer2Data16+KEigerBaseAddress)&0xffff);
+#elif defined(__MAWD__)
+	return KTicksPerMillisecond-(*(volatile TUint*)(KWindTimer2Value16+KWindBaseAddress)&0xffff);
+#elif defined(__MISA__) || defined(__MCOT__)
+	return *(volatile TUint*)KHwRwOstOscr-iTriggerTime;
+#elif defined(__MI920__) || defined(__NI1136__)
+	return KTicksPerMillisecond-(*(volatile TUint*)(KHwCounterTimer2+KHoTimerValue)&0xffff);
+#elif defined(__IS_OMAP1610__)
+	return KTicksPerMillisecond - *(volatile TUint*)(KHwBaseOSTimer1Reg+KHoOSTimer_READ_TIM);
+#elif defined(__IS_OMAP2420__) || defined(__WAKEUP_3430__)
+	return (*(volatile TUint*)(iTimerInfo.iAddress + KHoGpTimer_TCRR)) - iTimerLoadValue;
+#elif defined(__X86PC__)
+	return 1194 - __HwTimer();
+#elif defined(__RVEMUBOARD__)
+	return KTicksPerMillisecond-(*(volatile TUint*)(KHwCounterTimer1+KHoTimerValue)&0xffff);
+#elif defined(__NE1_TB__)
+	return NETimer::Timer(0).iTimerCount;	// counts up, reset timer + interrupt on match
+#endif
+	}
+
+#if !defined(__SMP__)
+#if !defined(__EPOC32__) || !defined(__CPU_X86)
+extern TUint IntStackPtr();
+#endif
+#endif
+
+DECLARE_STANDARD_LDD()
+	{
+	return new DDeviceLatency;
+	}
+
+DDeviceLatency::DDeviceLatency()
+//
+// Constructor
+//
+	{
+	//iParseMask=0;
+	//iUnitsMask=0;
+	iVersion=TVersion(1,0,1);
+	}
+
+TInt DDeviceLatency::Install()
+//
+// Install the device driver.
+//
+	{
+	TInt r=SetName(&KLddName);
+	return r;
+	}
+
+void DDeviceLatency::GetCaps(TDes8& aDes) const
+//
+// Return the Comm capabilities.
+//
+	{
+	}
+
+TInt DDeviceLatency::Create(DLogicalChannelBase*& aChannel)
+//
+// Create a channel on the device.
+//
+	{
+	aChannel=new DLatency;
+	return aChannel?KErrNone:KErrNoMemory;
+	}
+
+DLatency::DLatency()
+	:	iMsCallBack(MsCallBack,this),
+		iMsDfc(MsDfc,this,NULL,1)
+//
+// Constructor
+//
+	{
+#if !defined(__SMP__)
+#if !defined(__EPOC32__) || !defined(__CPU_X86)
+	iIntStackTop=(TUint*)IntStackPtr();
+#endif
+#endif
+#if defined(__MISA__) || defined(__MCOT__)
+	iTickIncrement=KOstTicks*KFudgeFactor;
+#endif
+#if defined(__IS_OMAP2420__) || defined(__WAKEUP_3430__)
+	iTimerInfo.iAddress = 0;
+#endif
+	}
+
+DLatency::~DLatency()
+//
+// Destructor
+//
+	{
+	iOff = (TUint8)ETrue;
+	StopTimer();
+	iMsDfc.Cancel();
+
+	if (iRtDfcQ)
+		iRtDfcQ->Destroy();
+
+	if (iPowerHandler)
+		{
+		iPowerHandler->Remove();
+		delete iPowerHandler;
+		}
+
+	Kern::SafeClose((DObject*&)iClient, NULL);
+	}
+
+TInt DLatency::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
+//
+// Create the channel from the passed info.
+//
+	{
+	if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer))
+		return KErrNotSupported;
+
+	// create the power handler
+	iPowerHandler = new DLatencyPowerHandler(this);
+	if (!iPowerHandler)
+		return KErrNoMemory;
+	iPowerHandler->Add();
+
+	// Allocate a kernel thread to run the DFC 
+	TInt r = Kern::DynamicDfcQCreate(iRtDfcQ, KNumPriorities-1,KThreadName);
+
+	if (r != KErrNone)
+		return r; 	
+
+	iMsDfc.SetDfcQ(iRtDfcQ);
+	iClient=&Kern::CurrentThread();
+	iClient->Open();
+	Kern::SetThreadPriority(KNumPriorities-2);
+	return KErrNone;
+	}
+
+#if defined(__MISA__) 
+// For SA1100/SA1110 use a separate timer on a FIQ interrupt (OST match 0)
+TInt DLatency::StartTimer()
+	{
+	TInt r=Interrupt::Bind(KIntIdOstMatchGeneral,MsCallBack,this);
+	if (r==KErrNone)
+		{
+		TSa1100::ModifyIntLevels(0,KHtIntsOstMatchGeneral);	// route new timer interrupt to FIQ
+		TSa1100::SetOstMatchEOI(KHwOstMatchGeneral);
+		TUint oscr=TSa1100::OstData();
+		iTriggerTime=oscr+KOstTicks*KFudgeFactor;
+		TSa1100::SetOstMatch(KHwOstMatchGeneral,iTriggerTime);
+		TSa1100::EnableOstInterrupt(KHwOstMatchGeneral);
+		Interrupt::Enable(KIntIdOstMatchGeneral);
+		}
+	return r;
+	}
+#elif defined(__MCOT__)
+// For Cotulla use a separate timer on a FIQ interrupt (OST match 0)
+TInt DLatency::StartTimer()
+	{
+	TInt r=Interrupt::Bind(KIntIdOstMatchGeneral,MsCallBack,this);
+	if (r==KErrNone)
+		{
+		TCotulla::ModifyIntLevels(0,KHtIntsOstMatchGeneral);	// route new timer interrupt to FIQ
+		TCotulla::SetOstMatchEOI(KHwOstMatchGeneral);
+		TUint oscr=TCotulla::OstData();
+		iTriggerTime=oscr+KOstTicks*KFudgeFactor;
+		TCotulla::SetOstMatch(iTriggerTime,KHwOstMatchGeneral);
+		TCotulla::EnableOstInterrupt(KHwOstMatchGeneral);
+		Interrupt::Enable(KIntIdOstMatchGeneral);
+		}
+	return r;
+	}
+#elif defined(__IS_OMAP2420__) || defined(__WAKEUP_3430__)
+TInt DLatency::StartTimer()
+/* 
+ *  For OMAP2420 initialise a new timer to generate an interrupt every 1ms
+ */
+	{
+	__ASSERT_ALWAYS(!iTimerInfo.iAddress, Kern::Fault("D_Latncy: timer allocated twice.",
+													 iTimerInfo.iAddress));
+
+	// Get an available Timer from the system
+    TInt r = OmapTimerMgr::GetTimer(iGPTimerId, iTimerInfo);
+    if (KErrNone != r)
+    	{
+    	return r;
+    	}
+    	
+    // Configure the timer
+    r = ConfigureTimer();
+    if (KErrNone != r)
+    	{
+    	DisableTimer();
+    	return r;
+    	}
+    
+    // Bind to timer interrupt
+    r = Interrupt::Bind(iTimerInfo.iInterruptId, MsCallBack, this);
+    if (KErrNone != r)
+        {
+        DisableTimer();
+        return r;
+        }
+              
+    // Unmask timer IT in interrupt controller
+    r = Interrupt::Enable(iTimerInfo.iInterruptId);
+    if (KErrNone != r)
+		{
+		Interrupt::Unbind(iTimerInfo.iInterruptId);
+		DisableTimer();
+    	return r;
+    	}
+    
+    // Start timer
+    TOmap::ModifyRegister32(iTimerInfo.iAddress + KHoGpTimer_TCLR, KClear32,
+                        KHtGpTimer_TCLR_St);
+        
+    return KErrNone;
+	}
+
+void DLatency::DisableTimer()
+/*
+ *	Disable the interface and functional clock and mark the timer as available 
+ */
+	{
+	  // Stop timer
+    TOmap::ModifyRegister32(iTimerInfo.iAddress + KHoGpTimer_TCLR,
+                        KHtGpTimer_TCLR_St, KClear32);
+
+#if defined(__WAKEUP_3430__)
+    // Disable Timer clocks using Timer framework instead of using TPRcm direct calls for 3430
+    TInt r = OmapTimerMgr::DisableClocks(iGPTimerId);
+    if (r != KErrNone)
+        __ASSERT_ALWAYS(r, Kern::Fault("Timer clocks disable failed", 0)) ;
+#else
+	// Disable timer interface clock in PRCM
+	TPrcm::InterfaceClkCtrl(iTimerInfo.iPrcmDeviceId, EFalse);
+	
+	// Disable timer functional clock in PRCM
+	TPrcm::FunctionalClkCtrl(iTimerInfo.iPrcmDeviceId, EFalse);
+#endif
+
+	// Release the timer
+	OmapTimerMgr::ReleaseTimer(iGPTimerId);
+	
+	iTimerInfo.iAddress = 0;
+	}
+
+
+TInt DLatency::ConfigureTimer()
+/*
+ *	This method will configure a timer to:
+ *		-	run at the system clock (12Mhz)
+ *		-	no prescaler (disable TCLR[PRE])
+ *		-   autoreload and overflow interrupt enabled (TLDR will contain a
+ *			value to generate an interrupt every 1000microsec)
+ */
+	{
+
+#if defined(__WAKEUP_3430__)
+	// Enable Timer clocks using timer framework instead of TPrcm direct calls for 3430
+    TInt r = OmapTimerMgr::EnableClocks(iGPTimerId);
+    if (r != KErrNone)
+        __ASSERT_ALWAYS(r, Kern::Fault("Timer Clocks enable failed", 0)) ;
+
+	// Select the input clock to be system clock 
+    r = OmapTimerMgr::SetTimerClkSrc(iGPTimerId, ESysClk);
+#else
+	// Enable timer interface clock in PRCM  
+	TPrcm::InterfaceClkCtrl(iTimerInfo.iPrcmDeviceId, ETrue, ETrue);
+	// Enable timer functional clock in PRCM
+	TPrcm::FunctionalClkCtrl(iTimerInfo.iPrcmDeviceId, ETrue, ETrue);
+
+	// Select the input clock to be system clock 
+    TInt r = OmapTimerMgr::SetTimerClkSrc(iGPTimerId, ESysClk);
+#endif
+
+    if (KErrNone != r)	
+    	return r;
+
+    // Timer OCP configuration: - software reset
+    TOmap::SetRegister32( iTimerInfo.iAddress + KHoGpTimerTIOCP_CFG,
+                          KHtGpTimer_TIOCP_CFG_SoftReset);
+
+    // Wait for reset to be complete
+    TUint16 timeOut = 1000;
+    while ( !(TOmap::Register32(iTimerInfo.iAddress + KHoGpTimer_TISTAT) & 
+    			KHtGpTimer_TISTAT_ResetComplete)
+    			&& --timeOut);
+    
+   // Check if the timer has been reset or we hit the timeout
+   __ASSERT_ALWAYS((TOmap::Register32(iTimerInfo.iAddress + KHoGpTimer_TISTAT) & 
+    			KHtGpTimer_TISTAT_ResetComplete), Kern::Fault("D_Latncy: failed to reset timer.",
+													 iGPTimerId));
+	
+    // Set PRE to be 0, PTV value is ignored, AutoReload is enabled
+    TOmap::SetRegister32(iTimerInfo.iAddress + KHoGpTimer_TCLR, KHtGpTimer_TCLR_AR );
+
+	//PTV argument is 0 because of TCLR[PRE] = 0 (prescaling disabled)
+	TInt timerPTV = 0;
+	
+	// Calculate clock frequence from the ticks per ms
+	TInt timerClkSrcFreq = KTicksPerMillisecond * 1000;
+    
+    iTimerLoadValue = OmapTimerMgr::TimerLoadValue(/*microsecs*/1000, timerClkSrcFreq, timerPTV);                          
+
+	// First, load value in TCRR and TLDR registers
+    TOmap::SetRegister32(iTimerInfo.iAddress + KHoGpTimer_TCRR, iTimerLoadValue);
+    TOmap::SetRegister32(iTimerInfo.iAddress + KHoGpTimer_TLDR, iTimerLoadValue);
+
+    // Enable overflow interrupt
+    TOmap::SetRegister32(iTimerInfo.iAddress + KHoGpTimer_TIER,
+                         KHtGpTimer_TIER_OverFlow);
+
+    return KErrNone;
+	}
+#else
+TInt DLatency::StartTimer()
+	{
+	iMsCallBack.OneShot(KTickPeriodMs*KFudgeFactor);
+	return KErrNone;
+	}
+#endif
+
+#if defined(__MISA__) 
+// For SA1100/SA1110 use a separate timer on a FIQ interrupt (OST match 0)
+void DLatency::StopTimer()
+	{
+	TSa1100::ModifyIntLevels(KHtIntsOstMatchGeneral,0);
+	TSa1100::DisableOstInterrupt(KHwOstMatchGeneral);
+	Interrupt::Disable(KIntIdOstMatchGeneral);
+	Interrupt::Unbind(KIntIdOstMatchGeneral);
+	TSa1100::SetOstMatchEOI(KHwOstMatchGeneral);
+	}
+#elif defined(__MCOT__)
+// For Cotulla use a separate timer on a FIQ interrupt (OST match 0)
+void DLatency::StopTimer()
+	{
+	TCotulla::ModifyIntLevels(KHtIntsOstMatchGeneral,0);
+	TCotulla::DisableOstInterrupt(KHwOstMatchGeneral);
+	Interrupt::Disable(KIntIdOstMatchGeneral);
+	Interrupt::Unbind(KIntIdOstMatchGeneral);
+	TCotulla::SetOstMatchEOI(KHwOstMatchGeneral);
+	}
+#elif defined(__IS_OMAP2420__) || defined(__WAKEUP_3430__)
+void DLatency::StopTimer()
+	{
+	Interrupt::Disable(iTimerInfo.iInterruptId);
+	Interrupt::Unbind(iTimerInfo.iInterruptId);
+	DisableTimer();
+	}
+#else
+void DLatency::StopTimer()
+	{
+	iMsCallBack.Cancel();
+	}
+#endif
+
+TInt DLatency::Request(TInt aFunction, TAny* a1, TAny* a2)
+//
+// Client requests
+//
+	{
+	// Kern::Printf("DLatency::Request() 0x%x)\n", aFunction);
+	TInt r=KErrNone;
+	switch (aFunction)
+		{
+		case RLatency::EControlStart:
+			iStarted = (TUint8)ETrue;
+			StartTimer();
+			break;
+		case RLatency::EControlTicksPerMs:
+			r=KTicksPerMillisecond;
+			break;
+		case RLatency::EControlGetResults:
+			iResults.iUserThreadTicks = Ticks();
+			kumemput32(a1, &iResults, sizeof(SLatencyResults));
+			break;
+		default:
+			r = KErrNotSupported;
+			break;
+		}
+	return(r);
+	}
+
+#ifdef __CAPTURE_EXTRAS
+extern void CaptureExtras(SLatencyResults&);
+#endif
+
+#if !defined(__MISA__) && !defined(__MCOT__)
+void DLatency::MsCallBack(TAny* aPtr)
+	{
+	DLatency* pL = (DLatency*)aPtr;
+#if defined(__IS_OMAP2420__) || defined(__WAKEUP_3430__)
+	pL->iResults.iIntTicks = pL->Ticks();
+	TOmap::SetRegister32(pL->iTimerInfo.iAddress + KHoGpTimer_TISR, KHtGpTimer_TISR_OverFlow);
+#else
+	pL->iResults.iIntTicks = Ticks();
+#endif
+#ifdef __CAPTURE_EXTRAS
+	CaptureExtras(pL->iResults);
+#endif
+#if defined(__EPOC32__) && defined(__CPU_X86)
+	pL->iResults.iIntRetAddr = X86::IrqReturnAddress();
+#elif defined(__CPU_ARM) && defined(__SMP__)
+	pL->iResults.iIntRetAddr = Arm::IrqReturnAddress();
+#else
+	pL->iResults.iIntRetAddr=(pL->iIntStackTop)[-1];
+#endif
+	if (!pL->iOff)
+		{
+		pL->iMsCallBack.Again(KTickPeriodMs*KFudgeFactor);
+		pL->iMsDfc.Add();
+		}
+	}
+#endif
+
+void DLatency::MsDfc(TAny* aPtr)
+	{
+	DLatency* pL = (DLatency*)aPtr;
+	pL->iResults.iKernThreadTicks=pL->Ticks();
+	NKern::ThreadRequestSignal(&pL->iClient->iNThread);
+	}
+
+DLatencyPowerHandler::DLatencyPowerHandler(DLatency* aChannel)
+	:	DPowerHandler(KLddName), 
+		iChannel(aChannel)
+	{
+	}
+
+void DLatencyPowerHandler::PowerUp()
+	{
+	iChannel->iOff = (TUint8)EFalse;
+	if (iChannel->iStarted)
+		iChannel->StartTimer();
+	PowerUpDone();
+	}
+
+void DLatencyPowerHandler::PowerDown(TPowerState)
+	{
+	iChannel->iOff = (TUint8)ETrue;
+	iChannel->StopTimer();
+	PowerDownDone();
+	}
+
+
+