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 |
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 |