diff -r 000000000000 -r 96e5fb8b040d kerneltest/e32test/realtime/d_latncy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/realtime/d_latncy.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,569 @@ +// 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 +#elif defined(__MAWD__) +#include +#elif defined(__MISA__) +#include +#elif defined(__MCOT__) +#include +#elif defined(__MI920__) || defined(__NI1136__) +#include +//#define FREE_RUNNING_MODE // runs the millisecond timer in free running mode +#elif defined(__IS_OMAP1610__) +#include +#include +#elif defined(__IS_OMAP2420__) || defined(__WAKEUP_3430__) +#include +#include +#elif defined(__EPOC32__) && defined(__CPU_X86) +#include +#include +#elif defined(__RVEMUBOARD__) +#include +#elif defined(__NE1_TB__) +#include +#endif + +#ifdef __CPU_ARM +#include +#endif + +#include //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; + +#ifdef CPU_AFFINITY_ANY + NKern::ThreadSetCpuAffinity((NThread*)(iRtDfcQ->iThread), KCpuAffinityAny); +#endif + + 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(); + } + + +