kernel/eka/nkernsmp/arm/ncutils.cpp
changeset 201 43365a9b78a3
parent 90 947f0dc9f7a8
equal deleted inserted replaced
200:73ea206103e6 201:43365a9b78a3
    20 #include <arm_scu.h>
    20 #include <arm_scu.h>
    21 #include <arm_tmr.h>
    21 #include <arm_tmr.h>
    22 #include <nk_irq.h>
    22 #include <nk_irq.h>
    23 
    23 
    24 extern "C" {
    24 extern "C" {
    25 extern SVariantInterfaceBlock* VIB;
       
    26 
       
    27 extern TUint KernCoreStats_EnterIdle(TUint aCore);
    25 extern TUint KernCoreStats_EnterIdle(TUint aCore);
    28 extern void KernCoreStats_LeaveIdle(TInt aCookie,TUint aCore);
    26 extern void KernCoreStats_LeaveIdle(TInt aCookie,TUint aCore);
    29 
    27 
    30 extern void DetachComplete();
    28 extern void DetachComplete();
    31 extern void send_irq_ipi(TSubScheduler*, TInt);
    29 extern void send_irq_ipi(TSubScheduler*, TInt);
    32 }
    30 }
    33 
    31 
       
    32 TInt ClockFrequenciesChanged();
    34 
    33 
    35 
    34 
    36 /******************************************************************************
    35 /******************************************************************************
    37  * Spin lock
    36  * Spin lock
    38  ******************************************************************************/
    37  ******************************************************************************/
    87 #endif
    86 #endif
    88 
    87 
    89 void NKern::Init0(TAny* a)
    88 void NKern::Init0(TAny* a)
    90 	{
    89 	{
    91 	__KTRACE_OPT(KBOOT,DEBUGPRINT("VIB=%08x", a));
    90 	__KTRACE_OPT(KBOOT,DEBUGPRINT("VIB=%08x", a));
    92 	VIB = (SVariantInterfaceBlock*)a;
    91 	SVariantInterfaceBlock* v = (SVariantInterfaceBlock*)a;
    93 	__NK_ASSERT_ALWAYS(VIB && VIB->iVer==0 && VIB->iSize==sizeof(SVariantInterfaceBlock));
    92 	TheScheduler.iVIB = v;
    94 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iVer=%d iSize=%d", VIB->iVer, VIB->iSize));
    93 	__NK_ASSERT_ALWAYS(v && v->iVer==0 && v->iSize==sizeof(SVariantInterfaceBlock));
    95 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxCpuClock=%08x %08x", I64HIGH(VIB->iMaxCpuClock), I64LOW(VIB->iMaxCpuClock)));
    94 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iVer=%d iSize=%d", v->iVer, v->iSize));
    96 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxTimerClock=%u", VIB->iMaxTimerClock));
    95 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxCpuClock=%08x %08x", I64HIGH(v->iMaxCpuClock), I64LOW(v->iMaxCpuClock)));
    97 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iScuAddr=%08x", VIB->iScuAddr));
    96 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxTimerClock=%u", v->iMaxTimerClock));
    98 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iGicDistAddr=%08x", VIB->iGicDistAddr));
    97 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iScuAddr=%08x", v->iScuAddr));
    99 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iGicCpuIfcAddr=%08x", VIB->iGicCpuIfcAddr));
    98 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iGicDistAddr=%08x", v->iGicDistAddr));
   100 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iLocalTimerAddr=%08x", VIB->iLocalTimerAddr));
    99 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iGicCpuIfcAddr=%08x", v->iGicCpuIfcAddr));
   101 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iGlobalTimerAddr=%08x", VIB->iGlobalTimerAddr));
   100 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iLocalTimerAddr=%08x", v->iLocalTimerAddr));
       
   101 	__KTRACE_OPT(KBOOT,DEBUGPRINT("iGlobalTimerAddr=%08x", v->iGlobalTimerAddr));
   102 
   102 
   103 	TScheduler& s = TheScheduler;
   103 	TScheduler& s = TheScheduler;
   104 	s.iSX.iScuAddr = (ArmScu*)VIB->iScuAddr;
   104 	s.iSX.iScuAddr = (ArmScu*)v->iScuAddr;
   105 	s.iSX.iGicDistAddr = (GicDistributor*)VIB->iGicDistAddr;
   105 	s.iSX.iGicDistAddr = (GicDistributor*)v->iGicDistAddr;
   106 	s.iSX.iGicCpuIfcAddr = (GicCpuIfc*)VIB->iGicCpuIfcAddr;
   106 	s.iSX.iGicCpuIfcAddr = (GicCpuIfc*)v->iGicCpuIfcAddr;
   107 	s.iSX.iLocalTimerAddr = (ArmLocalTimer*)VIB->iLocalTimerAddr;
   107 	s.iSX.iLocalTimerAddr = (ArmLocalTimer*)v->iLocalTimerAddr;
   108 	s.iSX.iTimerMax = (VIB->iMaxTimerClock / 1);		// use prescaler value of 1
   108 	s.iSX.iTimerMax = (v->iMaxTimerClock / 1);		// use prescaler value of 1
   109 #ifdef	__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK
   109 #ifdef	__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK
   110 	s.iSX.iGlobalTimerAddr = (ArmGlobalTimer*)VIB->iGlobalTimerAddr;
   110 	s.iSX.iGlobalTimerAddr = (ArmGlobalTimer*)v->iGlobalTimerAddr;
       
   111 	s.iSX.iGTimerFreqRI.Set(v->iGTimerFreqR);
       
   112 	v->iGTimerFreqR = 0;
   111 #endif
   113 #endif
   112 
   114 
   113 	TInt i;
   115 	TInt i;
   114 	for (i=0; i<KMaxCpus; ++i)
   116 	for (i=0; i<KMaxCpus; ++i)
   115 		{
   117 		{
   116 		TSubScheduler& ss = TheSubSchedulers[i];
   118 		TSubScheduler& ss = TheSubSchedulers[i];
   117 		ss.iSSX.iCpuFreqM = KMaxTUint32;
   119 		ss.iSSX.iCpuFreqRI.Set(v->iCpuFreqR[i]);
   118 		ss.iSSX.iCpuFreqS = 0;
   120 		ss.iSSX.iTimerFreqRI.Set(v->iTimerFreqR[i]);
   119 		ss.iSSX.iCpuPeriodM = 0x80000000u;
   121 
   120 		ss.iSSX.iCpuPeriodS = 31;
   122 		v->iCpuFreqR[i] = 0;
   121 		ss.iSSX.iNTimerFreqM = KMaxTUint32;
   123 		v->iTimerFreqR[i] = 0;
   122 		ss.iSSX.iNTimerFreqS = 0;
   124 		UPerCpuUncached* u = v->iUncached[i];
   123 		ss.iSSX.iNTimerPeriodM = 0x80000000u;
       
   124 		ss.iSSX.iNTimerPeriodS = 31;
       
   125 		ss.iSSX.iTimerFreqM = KMaxTUint32;
       
   126 		ss.iSSX.iTimerFreqS = 0;
       
   127 		ss.iSSX.iTimerPeriodM = 0x80000000u;
       
   128 		ss.iSSX.iTimerPeriodS = 31;
       
   129 		ss.iSSX.iLastSyncTime = 0;
       
   130 		ss.iSSX.iTicksSinceLastSync = 0;
       
   131 		ss.iSSX.iLastTimerSet = 0;
       
   132 		ss.iSSX.iGapEstimate = 10<<16;
       
   133 		ss.iSSX.iGapCount = 0;
       
   134 		ss.iSSX.iTotalTicks = 0;
       
   135 		ss.iSSX.iDitherer = 1;
       
   136 		ss.iSSX.iFreqErrorEstimate = 0;
       
   137 		ss.iSSX.iFreqErrorLimit = 0x00100000;
       
   138 		ss.iSSX.iErrorIntegrator = 0;
       
   139 		ss.iSSX.iRefAtLastCorrection = 0;
       
   140 		ss.iSSX.iM = 4;
       
   141 		ss.iSSX.iN = 18;
       
   142 		ss.iSSX.iD = 3;
       
   143 		VIB->iTimerMult[i] = 0;
       
   144 		VIB->iCpuMult[i] = 0;
       
   145 		UPerCpuUncached* u = VIB->iUncached[i];
       
   146 		ss.iUncached = u;
   125 		ss.iUncached = u;
   147 		u->iU.iDetachCount = 0;
   126 		u->iU.iDetachCount = 0;
   148 		u->iU.iAttachCount = 0;
   127 		u->iU.iAttachCount = 0;
   149 		u->iU.iPowerOffReq = FALSE;
   128 		u->iU.iPowerOffReq = FALSE;
   150 		u->iU.iDetachCompleteFn = &DetachComplete;
   129 		u->iU.iDetachCompleteFn = &DetachComplete;
   151 		}
   130 		}
       
   131 	v->iFrqChgFn = &ClockFrequenciesChanged;
   152 	__e32_io_completion_barrier();
   132 	__e32_io_completion_barrier();
   153 	InterruptInit0();
   133 	InterruptInit0();
   154 	}
   134 	}
   155 
   135 
   156 /** Register the global IRQ handler
   136 /** Register the global IRQ handler
   372 	TUint32 arg = orig_cpus_not_idle & ~m;
   352 	TUint32 arg = orig_cpus_not_idle & ~m;
   373 	if (arg == 0)
   353 	if (arg == 0)
   374 		s.AllCpusIdle();
   354 		s.AllCpusIdle();
   375 	s.iIdleSpinLock.UnlockOnly();
   355 	s.iIdleSpinLock.UnlockOnly();
   376 
   356 
   377 	//TUint cookie = KernCoreStats::EnterIdle((TUint8)ss.iCpuNum);
       
   378 	TUint cookie = KernCoreStats_EnterIdle((TUint8)ss.iCpuNum);
   357 	TUint cookie = KernCoreStats_EnterIdle((TUint8)ss.iCpuNum);
   379 
   358 
   380 	arg |= retire;
   359 	arg |= retire;
   381 	NKIdle(arg);
   360 	NKIdle(arg);
   382 
       
   383 	//KernCoreStats::LeaveIdle(cookie, (TUint8)ss.iCpuNum);
       
   384 	KernCoreStats_LeaveIdle(cookie, (TUint8)ss.iCpuNum);
       
   385 
       
   386 
   361 
   387 	// interrupts have not been reenabled
   362 	// interrupts have not been reenabled
   388 	s.iIdleSpinLock.LockOnly();
   363 	s.iIdleSpinLock.LockOnly();
   389 
   364 
   390 	if (retire)
   365 	if (retire)
   413 		NKIdle(ci|m|SCpuIdleHandler::EPostamble);
   388 		NKIdle(ci|m|SCpuIdleHandler::EPostamble);
   414 		}
   389 		}
   415 	if (ci == 0)
   390 	if (ci == 0)
   416 		s.FirstBackFromIdle();
   391 		s.FirstBackFromIdle();
   417 
   392 
       
   393 	KernCoreStats_LeaveIdle(cookie, (TUint8)ss.iCpuNum);
       
   394 
   418 	if (retire)
   395 	if (retire)
   419 		{
   396 		{
   420 		s.iCCReactivateDfc.RawAdd();	// kick load balancer to give us some work
   397 		s.iCCReactivateDfc.RawAdd();	// kick load balancer to give us some work
   421 		if (event_kick)
   398 		if (event_kick)
   422 			send_irq_ipi(&ss, EQueueEvent_Kick);	// so that we will process pending events
   399 			send_irq_ipi(&ss, EQueueEvent_Kick);	// so that we will process pending events
   430 	return u->iDetachCount != u->iAttachCount;
   407 	return u->iDetachCount != u->iAttachCount;
   431 	}
   408 	}
   432 
   409 
   433 TBool TScheduler::CoreControlSupported()
   410 TBool TScheduler::CoreControlSupported()
   434 	{
   411 	{
   435 	return VIB->iCpuPowerUpFn != 0;
   412 	return TheScheduler.iVIB->iCpuPowerUpFn != 0;
   436 	}
   413 	}
   437 
   414 
   438 void TScheduler::CCInitiatePowerUp(TUint32 aCores)
   415 void TScheduler::CCInitiatePowerUp(TUint32 aCores)
   439 	{
   416 	{
   440 	TCpuPowerUpFn pUp = VIB->iCpuPowerUpFn;
   417 	TCpuPowerUpFn pUp = TheScheduler.iVIB->iCpuPowerUpFn;
   441 	if (pUp && aCores)
   418 	if (pUp && aCores)
   442 		{
   419 		{
   443 		TInt i;
   420 		TInt i;
   444 		for (i=0; i<KMaxCpus; ++i)
   421 		for (i=0; i<KMaxCpus; ++i)
   445 			{
   422 			{
   461 		}
   438 		}
   462 	}
   439 	}
   463 
   440 
   464 void TScheduler::CCIndirectPowerDown(TAny*)
   441 void TScheduler::CCIndirectPowerDown(TAny*)
   465 	{
   442 	{
   466 	TCpuPowerDownFn pDown = VIB->iCpuPowerDownFn;
   443 	TCpuPowerDownFn pDown = TheScheduler.iVIB->iCpuPowerDownFn;
   467 	if (pDown)
   444 	if (pDown)
   468 		{
   445 		{
   469 		TInt i;
   446 		TInt i;
   470 		for (i=0; i<KMaxCpus; ++i)
   447 		for (i=0; i<KMaxCpus; ++i)
   471 			{
   448 			{
   553 #else
   530 #else
   554 #error No definition for NKern::TimestampFrequency()
   531 #error No definition for NKern::TimestampFrequency()
   555 #endif
   532 #endif
   556 	}
   533 	}
   557 
   534 
       
   535 /******************************************************************************
       
   536  * Notify frequency changes
       
   537  ******************************************************************************/
       
   538 
       
   539 struct SFrequencies
       
   540 	{
       
   541 	void Populate();
       
   542 	void Apply();
       
   543 	TBool AddToQueue();
       
   544 
       
   545 	SFrequencies*	iNext;
       
   546 	TUint32			iWhich;
       
   547 	SRatioInv		iNewCpuRI[KMaxCpus];
       
   548 	SRatioInv		iNewTimerRI[KMaxCpus];
       
   549 	SRatioInv		iNewGTimerRI;
       
   550 	NFastSemaphore*	iSem;
       
   551 
       
   552 	static SFrequencies* volatile Head;
       
   553 	};
       
   554 
       
   555 SFrequencies* volatile SFrequencies::Head;
       
   556 
       
   557 TBool SFrequencies::AddToQueue()
       
   558 	{
       
   559 	SFrequencies* h = Head;
       
   560 	do	{
       
   561 		iNext = h;
       
   562 		} while(!__e32_atomic_cas_rel_ptr(&Head, &h, this));
       
   563 	return !h;	// TRUE if list was empty
       
   564 	}
       
   565 
       
   566 
       
   567 void SFrequencies::Populate()
       
   568 	{
       
   569 	TScheduler& s = TheScheduler;
       
   570 	TInt cpu;
       
   571 	iWhich = 0;
       
   572 	SRatio* ri = (SRatio*)__e32_atomic_swp_ord_ptr(&s.iVIB->iGTimerFreqR, 0);
       
   573 	if (ri)
       
   574 		{
       
   575 		iNewGTimerRI.Set(ri);
       
   576 		iWhich |= 0x80000000u;
       
   577 		}
       
   578 	for (cpu=0; cpu<s.iNumCpus; ++cpu)
       
   579 		{
       
   580 		TSubScheduler& ss = *s.iSub[cpu];
       
   581 		ri = (SRatio*)__e32_atomic_swp_ord_ptr(&s.iVIB->iCpuFreqR[cpu], 0);
       
   582 		if (ri)
       
   583 			{
       
   584 			iNewCpuRI[cpu].Set(ri);
       
   585 			iWhich |= ss.iCpuMask;
       
   586 			}
       
   587 		ri = (SRatio*)__e32_atomic_swp_ord_ptr(&s.iVIB->iTimerFreqR[cpu], 0);
       
   588 		if (ri)
       
   589 			{
       
   590 			iNewTimerRI[cpu].Set(ri);
       
   591 			iWhich |= (ss.iCpuMask<<8);
       
   592 			}
       
   593 		}
       
   594 	}
       
   595 
       
   596 #if defined(__NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__)
       
   597 extern void ArmGlobalTimerFreqChg(const SRatioInv* /*aNewGTimerFreqRI*/);
       
   598 #endif
       
   599 
       
   600 void SFrequencies::Apply()
       
   601 	{
       
   602 	if (!iWhich)
       
   603 		return;
       
   604 	TScheduler& s = TheScheduler;
       
   605 	TStopIPI ipi;
       
   606 	TUint32 stopped = ipi.StopCPUs();
       
   607 	TInt cpu;
       
   608 	TUint32 wait = 0;
       
   609 	for (cpu=0; cpu<s.iNumCpus; ++cpu)
       
   610 		{
       
   611 		TSubScheduler& ss = *s.iSub[cpu];
       
   612 		TUint32 m = 1u<<cpu;
       
   613 		TUint32 m2 = m | (m<<8);
       
   614 		if (stopped & m)
       
   615 			{
       
   616 			// CPU is running so let it update
       
   617 			if (iWhich & m2)
       
   618 				{
       
   619 				if (iWhich & m)
       
   620 					ss.iSSX.iNewCpuFreqRI = &iNewCpuRI[cpu];
       
   621 				if (iWhich & (m<<8))
       
   622 					ss.iSSX.iNewTimerFreqRI = &iNewTimerRI[cpu];
       
   623 				ss.iRescheduleNeededFlag = 1;
       
   624 				wait |= m;
       
   625 				}
       
   626 			}
       
   627 		else
       
   628 			{
       
   629 			// CPU is not running so update directly
       
   630 			if (iWhich & m)
       
   631 				{
       
   632 				ss.iSSX.iCpuFreqRI = iNewCpuRI[cpu];
       
   633 				}
       
   634 			if (iWhich & (m<<8))
       
   635 				{
       
   636 				ss.iSSX.iTimerFreqRI = iNewTimerRI[cpu];
       
   637 				}
       
   638 			}
       
   639 		}
       
   640 #if defined(__NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__)
       
   641 	if (iWhich & 0x80000000u)
       
   642 		{
       
   643 		ArmGlobalTimerFreqChg(&iNewGTimerRI);
       
   644 		}
       
   645 #endif
       
   646 	ipi.ReleaseCPUs();	// this CPU handled here
       
   647 	while(wait)
       
   648 		{
       
   649 		cpu = __e32_find_ls1_32(wait);
       
   650 		TSubScheduler& ss = *s.iSub[cpu];
       
   651 		if (!ss.iSSX.iNewCpuFreqRI && !ss.iSSX.iNewTimerFreqRI)
       
   652 			wait &= ~ss.iCpuMask;
       
   653 		__chill();
       
   654 		}
       
   655 	}
       
   656 
       
   657 void TScheduler::DoFrequencyChanged(TAny*)
       
   658 	{
       
   659 	SFrequencies* list = (SFrequencies*)__e32_atomic_swp_ord_ptr(&SFrequencies::Head, 0);
       
   660 	if (!list)
       
   661 		return;
       
   662 	list->Populate();
       
   663 	list->Apply();
       
   664 	SFrequencies* rev = 0;
       
   665 	while (list)
       
   666 		{
       
   667 		SFrequencies* next = list->iNext;
       
   668 		list->iNext = rev;
       
   669 		rev = list;
       
   670 		list = next;
       
   671 		}
       
   672 	while (rev)
       
   673 		{
       
   674 		NFastSemaphore* s = rev->iSem;
       
   675 		rev = rev->iNext;
       
   676 		NKern::FSSignal(s);
       
   677 		}
       
   678 	}
       
   679 
       
   680 TInt ClockFrequenciesChanged()
       
   681 	{
       
   682 	TScheduler& s = TheScheduler;
       
   683 	NFastSemaphore sem(0);
       
   684 	SFrequencies f;
       
   685 	f.iSem = &sem;
       
   686 	NThread* ct = NKern::CurrentThread();
       
   687 	NThread* lbt = TScheduler::LBThread();
       
   688 	NKern::ThreadEnterCS();
       
   689 	TBool first = f.AddToQueue();
       
   690 	if (!lbt || lbt == ct)
       
   691 		TScheduler::DoFrequencyChanged(&s);
       
   692 	else if (first)
       
   693 		s.iFreqChgDfc.Enque();
       
   694 	NKern::FSWait(&sem);
       
   695 	NKern::ThreadLeaveCS();
       
   696 	return KErrNone;
       
   697 	}
       
   698