diff -r 73ea206103e6 -r 43365a9b78a3 kernel/eka/nkernsmp/arm/ncutils.cpp --- a/kernel/eka/nkernsmp/arm/ncutils.cpp Wed Jun 23 19:44:53 2010 +0300 +++ b/kernel/eka/nkernsmp/arm/ncutils.cpp Tue Jul 06 15:50:07 2010 +0300 @@ -22,8 +22,6 @@ #include extern "C" { -extern SVariantInterfaceBlock* VIB; - extern TUint KernCoreStats_EnterIdle(TUint aCore); extern void KernCoreStats_LeaveIdle(TInt aCookie,TUint aCore); @@ -31,6 +29,7 @@ extern void send_irq_ipi(TSubScheduler*, TInt); } +TInt ClockFrequenciesChanged(); /****************************************************************************** @@ -89,66 +88,47 @@ void NKern::Init0(TAny* a) { __KTRACE_OPT(KBOOT,DEBUGPRINT("VIB=%08x", a)); - VIB = (SVariantInterfaceBlock*)a; - __NK_ASSERT_ALWAYS(VIB && VIB->iVer==0 && VIB->iSize==sizeof(SVariantInterfaceBlock)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iVer=%d iSize=%d", VIB->iVer, VIB->iSize)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxCpuClock=%08x %08x", I64HIGH(VIB->iMaxCpuClock), I64LOW(VIB->iMaxCpuClock))); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxTimerClock=%u", VIB->iMaxTimerClock)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iScuAddr=%08x", VIB->iScuAddr)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iGicDistAddr=%08x", VIB->iGicDistAddr)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iGicCpuIfcAddr=%08x", VIB->iGicCpuIfcAddr)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iLocalTimerAddr=%08x", VIB->iLocalTimerAddr)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iGlobalTimerAddr=%08x", VIB->iGlobalTimerAddr)); + SVariantInterfaceBlock* v = (SVariantInterfaceBlock*)a; + TheScheduler.iVIB = v; + __NK_ASSERT_ALWAYS(v && v->iVer==0 && v->iSize==sizeof(SVariantInterfaceBlock)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iVer=%d iSize=%d", v->iVer, v->iSize)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxCpuClock=%08x %08x", I64HIGH(v->iMaxCpuClock), I64LOW(v->iMaxCpuClock))); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxTimerClock=%u", v->iMaxTimerClock)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iScuAddr=%08x", v->iScuAddr)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iGicDistAddr=%08x", v->iGicDistAddr)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iGicCpuIfcAddr=%08x", v->iGicCpuIfcAddr)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iLocalTimerAddr=%08x", v->iLocalTimerAddr)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iGlobalTimerAddr=%08x", v->iGlobalTimerAddr)); TScheduler& s = TheScheduler; - s.iSX.iScuAddr = (ArmScu*)VIB->iScuAddr; - s.iSX.iGicDistAddr = (GicDistributor*)VIB->iGicDistAddr; - s.iSX.iGicCpuIfcAddr = (GicCpuIfc*)VIB->iGicCpuIfcAddr; - s.iSX.iLocalTimerAddr = (ArmLocalTimer*)VIB->iLocalTimerAddr; - s.iSX.iTimerMax = (VIB->iMaxTimerClock / 1); // use prescaler value of 1 + s.iSX.iScuAddr = (ArmScu*)v->iScuAddr; + s.iSX.iGicDistAddr = (GicDistributor*)v->iGicDistAddr; + s.iSX.iGicCpuIfcAddr = (GicCpuIfc*)v->iGicCpuIfcAddr; + s.iSX.iLocalTimerAddr = (ArmLocalTimer*)v->iLocalTimerAddr; + s.iSX.iTimerMax = (v->iMaxTimerClock / 1); // use prescaler value of 1 #ifdef __CPU_ARM_HAS_GLOBAL_TIMER_BLOCK - s.iSX.iGlobalTimerAddr = (ArmGlobalTimer*)VIB->iGlobalTimerAddr; + s.iSX.iGlobalTimerAddr = (ArmGlobalTimer*)v->iGlobalTimerAddr; + s.iSX.iGTimerFreqRI.Set(v->iGTimerFreqR); + v->iGTimerFreqR = 0; #endif TInt i; for (i=0; iiTimerMult[i] = 0; - VIB->iCpuMult[i] = 0; - UPerCpuUncached* u = VIB->iUncached[i]; + ss.iSSX.iCpuFreqRI.Set(v->iCpuFreqR[i]); + ss.iSSX.iTimerFreqRI.Set(v->iTimerFreqR[i]); + + v->iCpuFreqR[i] = 0; + v->iTimerFreqR[i] = 0; + UPerCpuUncached* u = v->iUncached[i]; ss.iUncached = u; u->iU.iDetachCount = 0; u->iU.iAttachCount = 0; u->iU.iPowerOffReq = FALSE; u->iU.iDetachCompleteFn = &DetachComplete; } + v->iFrqChgFn = &ClockFrequenciesChanged; __e32_io_completion_barrier(); InterruptInit0(); } @@ -374,16 +354,11 @@ s.AllCpusIdle(); s.iIdleSpinLock.UnlockOnly(); - //TUint cookie = KernCoreStats::EnterIdle((TUint8)ss.iCpuNum); TUint cookie = KernCoreStats_EnterIdle((TUint8)ss.iCpuNum); arg |= retire; NKIdle(arg); - //KernCoreStats::LeaveIdle(cookie, (TUint8)ss.iCpuNum); - KernCoreStats_LeaveIdle(cookie, (TUint8)ss.iCpuNum); - - // interrupts have not been reenabled s.iIdleSpinLock.LockOnly(); @@ -415,6 +390,8 @@ if (ci == 0) s.FirstBackFromIdle(); + KernCoreStats_LeaveIdle(cookie, (TUint8)ss.iCpuNum); + if (retire) { s.iCCReactivateDfc.RawAdd(); // kick load balancer to give us some work @@ -432,12 +409,12 @@ TBool TScheduler::CoreControlSupported() { - return VIB->iCpuPowerUpFn != 0; + return TheScheduler.iVIB->iCpuPowerUpFn != 0; } void TScheduler::CCInitiatePowerUp(TUint32 aCores) { - TCpuPowerUpFn pUp = VIB->iCpuPowerUpFn; + TCpuPowerUpFn pUp = TheScheduler.iVIB->iCpuPowerUpFn; if (pUp && aCores) { TInt i; @@ -463,7 +440,7 @@ void TScheduler::CCIndirectPowerDown(TAny*) { - TCpuPowerDownFn pDown = VIB->iCpuPowerDownFn; + TCpuPowerDownFn pDown = TheScheduler.iVIB->iCpuPowerDownFn; if (pDown) { TInt i; @@ -555,3 +532,167 @@ #endif } +/****************************************************************************** + * Notify frequency changes + ******************************************************************************/ + +struct SFrequencies + { + void Populate(); + void Apply(); + TBool AddToQueue(); + + SFrequencies* iNext; + TUint32 iWhich; + SRatioInv iNewCpuRI[KMaxCpus]; + SRatioInv iNewTimerRI[KMaxCpus]; + SRatioInv iNewGTimerRI; + NFastSemaphore* iSem; + + static SFrequencies* volatile Head; + }; + +SFrequencies* volatile SFrequencies::Head; + +TBool SFrequencies::AddToQueue() + { + SFrequencies* h = Head; + do { + iNext = h; + } while(!__e32_atomic_cas_rel_ptr(&Head, &h, this)); + return !h; // TRUE if list was empty + } + + +void SFrequencies::Populate() + { + TScheduler& s = TheScheduler; + TInt cpu; + iWhich = 0; + SRatio* ri = (SRatio*)__e32_atomic_swp_ord_ptr(&s.iVIB->iGTimerFreqR, 0); + if (ri) + { + iNewGTimerRI.Set(ri); + iWhich |= 0x80000000u; + } + for (cpu=0; cpuiCpuFreqR[cpu], 0); + if (ri) + { + iNewCpuRI[cpu].Set(ri); + iWhich |= ss.iCpuMask; + } + ri = (SRatio*)__e32_atomic_swp_ord_ptr(&s.iVIB->iTimerFreqR[cpu], 0); + if (ri) + { + iNewTimerRI[cpu].Set(ri); + iWhich |= (ss.iCpuMask<<8); + } + } + } + +#if defined(__NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) +extern void ArmGlobalTimerFreqChg(const SRatioInv* /*aNewGTimerFreqRI*/); +#endif + +void SFrequencies::Apply() + { + if (!iWhich) + return; + TScheduler& s = TheScheduler; + TStopIPI ipi; + TUint32 stopped = ipi.StopCPUs(); + TInt cpu; + TUint32 wait = 0; + for (cpu=0; cpuPopulate(); + list->Apply(); + SFrequencies* rev = 0; + while (list) + { + SFrequencies* next = list->iNext; + list->iNext = rev; + rev = list; + list = next; + } + while (rev) + { + NFastSemaphore* s = rev->iSem; + rev = rev->iNext; + NKern::FSSignal(s); + } + } + +TInt ClockFrequenciesChanged() + { + TScheduler& s = TheScheduler; + NFastSemaphore sem(0); + SFrequencies f; + f.iSem = &sem; + NThread* ct = NKern::CurrentThread(); + NThread* lbt = TScheduler::LBThread(); + NKern::ThreadEnterCS(); + TBool first = f.AddToQueue(); + if (!lbt || lbt == ct) + TScheduler::DoFrequencyChanged(&s); + else if (first) + s.iFreqChgDfc.Enque(); + NKern::FSWait(&sem); + NKern::ThreadLeaveCS(); + return KErrNone; + } +