34 extern void initialiseState(TInt aCpu, TSubScheduler* aSS); |
34 extern void initialiseState(TInt aCpu, TSubScheduler* aSS); |
35 |
35 |
36 extern "C" void ExcFault(TAny*); |
36 extern "C" void ExcFault(TAny*); |
37 |
37 |
38 extern TUint32 __mpid(); |
38 extern TUint32 __mpid(); |
39 extern void InitAPTimestamp(SNThreadCreateInfo& aInfo); |
39 extern void InitTimestamp(TSubScheduler* aSS, SNThreadCreateInfo& aInfo); |
40 |
40 |
41 TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial) |
41 TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial) |
42 { |
42 { |
43 // Assert ParameterBlockSize is not negative and is a multiple of 8 bytes |
43 // Assert ParameterBlockSize is not negative and is a multiple of 8 bytes |
44 __NK_ASSERT_ALWAYS((aInfo.iParameterBlockSize&0x80000007)==0); |
44 __NK_ASSERT_ALWAYS((aInfo.iParameterBlockSize&0x80000007)==0); |
45 __NK_ASSERT_ALWAYS(aInfo.iStackBase && aInfo.iStackSize>=aInfo.iParameterBlockSize+KNThreadMinStackSize); |
45 __NK_ASSERT_ALWAYS(aInfo.iStackBase && aInfo.iStackSize>=aInfo.iParameterBlockSize+KNThreadMinStackSize); |
46 TInt cpu = -1; |
46 TInt cpu = -1; |
|
47 TSubScheduler* ss = 0; |
47 new (this) NThread; |
48 new (this) NThread; |
48 if (aInitial) |
49 if (aInitial) |
49 { |
50 { |
50 cpu = __e32_atomic_add_ord32(&TheScheduler.iNumCpus, 1); |
51 cpu = __e32_atomic_add_ord32(&TheScheduler.iNumCpus, 1); |
51 aInfo.iCpuAffinity = cpu; |
52 aInfo.iCpuAffinity = cpu; |
52 // OK since we can't migrate yet |
53 // OK since we can't migrate yet |
53 TSubScheduler& ss = TheSubSchedulers[cpu]; |
54 ss = &TheSubSchedulers[cpu]; |
54 ss.iCurrentThread = this; |
55 ss->iCurrentThread = this; |
55 iRunCount64 = UI64LIT(1); |
56 ss->iDeferShutdown = 0; |
56 __KTRACE_OPT(KBOOT,DEBUGPRINT("Init: cpu=%d ss=%08x", cpu, &ss)); |
57 iRunCount.i64 = UI64LIT(1); |
|
58 iActiveState = 1; |
|
59 __KTRACE_OPT(KBOOT,DEBUGPRINT("Init: cpu=%d ss=%08x", cpu, ss)); |
57 if (cpu) |
60 if (cpu) |
58 { |
61 { |
59 initialiseState(cpu,&ss); |
62 initialiseState(cpu,ss); |
60 |
63 |
61 ArmLocalTimer& T = LOCAL_TIMER; |
64 ArmLocalTimer& T = LOCAL_TIMER; |
62 T.iWatchdogDisable = E_ArmTmrWDD_1; |
65 T.iWatchdogDisable = E_ArmTmrWDD_1; |
63 T.iWatchdogDisable = E_ArmTmrWDD_2; |
66 T.iWatchdogDisable = E_ArmTmrWDD_2; |
64 T.iTimerCtrl = 0; |
67 T.iTimerCtrl = 0; |
67 T.iWatchdogIntStatus = E_ArmTmrIntStatus_Event; |
70 T.iWatchdogIntStatus = E_ArmTmrIntStatus_Event; |
68 |
71 |
69 NIrq::HwInit2AP(); |
72 NIrq::HwInit2AP(); |
70 T.iTimerCtrl = E_ArmTmrCtrl_IntEn | E_ArmTmrCtrl_Reload | E_ArmTmrCtrl_Enable; |
73 T.iTimerCtrl = E_ArmTmrCtrl_IntEn | E_ArmTmrCtrl_Reload | E_ArmTmrCtrl_Enable; |
71 |
74 |
72 __e32_atomic_ior_ord32(&TheScheduler.iActiveCpus1, 1<<cpu); |
75 __e32_atomic_ior_ord32(&TheScheduler.iThreadAcceptCpus, 1<<cpu); |
73 __e32_atomic_ior_ord32(&TheScheduler.iActiveCpus2, 1<<cpu); |
76 __e32_atomic_ior_ord32(&TheScheduler.iIpiAcceptCpus, 1<<cpu); |
74 __e32_atomic_ior_ord32(&TheScheduler.iCpusNotIdle, 1<<cpu); |
77 __e32_atomic_ior_ord32(&TheScheduler.iCpusNotIdle, 1<<cpu); |
|
78 __e32_atomic_add_ord32(&TheScheduler.iCCRequestLevel, 1); |
75 __KTRACE_OPT(KBOOT,DEBUGPRINT("AP MPID=%08x",__mpid())); |
79 __KTRACE_OPT(KBOOT,DEBUGPRINT("AP MPID=%08x",__mpid())); |
76 } |
80 } |
77 else |
81 else |
78 { |
82 { |
79 Arm::DefaultDomainAccess = Arm::Dacr(); |
83 Arm::DefaultDomainAccess = Arm::Dacr(); |
126 } |
130 } |
127 else |
131 else |
128 { |
132 { |
129 NKern::EnableAllInterrupts(); |
133 NKern::EnableAllInterrupts(); |
130 |
134 |
|
135 #if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined(__NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) |
|
136 |
|
137 if (cpu == 0) |
|
138 { |
|
139 // start global timer if necessary |
|
140 ArmGlobalTimer& GT = GLOBAL_TIMER; |
|
141 if (!(GT.iTimerCtrl & E_ArmGTmrCtrl_TmrEnb)) |
|
142 { |
|
143 // timer not currently enabled |
|
144 GT.iTimerCtrl = 0; |
|
145 __e32_io_completion_barrier(); |
|
146 GT.iTimerStatus = E_ArmGTmrStatus_Event; |
|
147 __e32_io_completion_barrier(); |
|
148 GT.iTimerCountLow = 0; |
|
149 GT.iTimerCountHigh = 0; |
|
150 __e32_io_completion_barrier(); |
|
151 GT.iTimerCtrl = E_ArmGTmrCtrl_TmrEnb; // enable timer with prescale factor of 1 |
|
152 __e32_io_completion_barrier(); |
|
153 } |
|
154 } |
|
155 |
|
156 #endif |
|
157 |
131 // start local timer |
158 // start local timer |
132 ArmLocalTimer& T = LOCAL_TIMER; |
159 ArmLocalTimer& T = LOCAL_TIMER; |
133 T.iTimerCtrl = E_ArmTmrCtrl_IntEn | E_ArmTmrCtrl_Reload | E_ArmTmrCtrl_Enable; |
160 T.iTimerCtrl = E_ArmTmrCtrl_IntEn | E_ArmTmrCtrl_Reload | E_ArmTmrCtrl_Enable; |
134 |
161 // Initialise timestamp |
135 // synchronize AP's timestamp with BP's |
162 InitTimestamp(ss, aInfo); |
136 if (cpu>0) |
163 } |
137 InitAPTimestamp(aInfo); |
164 AddToEnumerateList(); |
138 } |
165 InitLbInfo(); |
139 #ifdef BTRACE_THREAD_IDENTIFICATION |
166 #ifdef BTRACE_THREAD_IDENTIFICATION |
140 BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this); |
167 BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this); |
141 #endif |
168 #endif |
142 return KErrNone; |
169 return KErrNone; |
143 } |
170 } |
182 DEBUGPRINT("R13Svc=%08x R14Svc=%08x SpsrSvc=%08x",a.iR13Svc,a.iR14Svc,a.iSpsrSvc); |
209 DEBUGPRINT("R13Svc=%08x R14Svc=%08x SpsrSvc=%08x",a.iR13Svc,a.iR14Svc,a.iSpsrSvc); |
183 |
210 |
184 TInt irq = NKern::DisableAllInterrupts(); |
211 TInt irq = NKern::DisableAllInterrupts(); |
185 TSubScheduler& ss = SubScheduler(); |
212 TSubScheduler& ss = SubScheduler(); |
186 NThreadBase* ct = ss.iCurrentThread; |
213 NThreadBase* ct = ss.iCurrentThread; |
187 TInt inc = TInt(ss.i_IrqNestCount); |
214 TInt inc = TInt(ss.iSSX.iIrqNestCount); |
188 TInt cpu = ss.iCpuNum; |
215 TInt cpu = ss.iCpuNum; |
189 TInt klc = ss.iKernLockCount; |
216 TInt klc = ss.iKernLockCount; |
190 NKern::RestoreInterrupts(irq); |
217 NKern::RestoreInterrupts(irq); |
191 DEBUGPRINT("Thread %T, CPU %d, KLCount=%d, IrqNest=%d", ct, cpu, klc, inc); |
218 DEBUGPRINT("Thread %T, CPU %d, KLCount=%d, IrqNest=%d", ct, cpu, klc, inc); |
192 } |
219 } |
1055 return 1; |
1082 return 1; |
1056 } |
1083 } |
1057 return 0; |
1084 return 0; |
1058 } |
1085 } |
1059 |
1086 |
1060 /** Return the total CPU time so far used by the specified thread. |
|
1061 |
|
1062 @return The total CPU time in units of 1/NKern::CpuTimeMeasFreq(). |
|
1063 */ |
|
1064 EXPORT_C TUint64 NKern::ThreadCpuTime(NThread* aThread) |
|
1065 { |
|
1066 TSubScheduler* ss = 0; |
|
1067 NKern::Lock(); |
|
1068 aThread->AcqSLock(); |
|
1069 if (aThread->i_NThread_Initial) |
|
1070 ss = &TheSubSchedulers[aThread->iLastCpu]; |
|
1071 else if (aThread->iReady && aThread->iParent->iReady) |
|
1072 ss = &TheSubSchedulers[aThread->iParent->iReady & NSchedulable::EReadyCpuMask]; |
|
1073 if (ss) |
|
1074 ss->iReadyListLock.LockOnly(); |
|
1075 TUint64 t = aThread->iTotalCpuTime64; |
|
1076 if (aThread->iCurrent || (aThread->i_NThread_Initial && !ss->iCurrentThread)) |
|
1077 t += (NKern::Timestamp() - ss->iLastTimestamp64); |
|
1078 if (ss) |
|
1079 ss->iReadyListLock.UnlockOnly(); |
|
1080 aThread->RelSLock(); |
|
1081 NKern::Unlock(); |
|
1082 return t; |
|
1083 } |
|
1084 |
1087 |
1085 TInt NKern::QueueUserModeCallback(NThreadBase* aThread, TUserModeCallback* aCallback) |
1088 TInt NKern::QueueUserModeCallback(NThreadBase* aThread, TUserModeCallback* aCallback) |
1086 { |
1089 { |
1087 __e32_memory_barrier(); |
1090 __e32_memory_barrier(); |
1088 if (aCallback->iNext != KUserModeCallbackUnqueued) |
1091 if (aCallback->iNext != KUserModeCallbackUnqueued) |
1089 return KErrInUse; |
1092 return KErrInUse; |
|
1093 if (aThread->i_NThread_Initial) |
|
1094 return KErrArgument; |
1090 TInt result = KErrDied; |
1095 TInt result = KErrDied; |
1091 NKern::Lock(); |
1096 NKern::Lock(); |
1092 TUserModeCallback* listHead = aThread->iUserModeCallbacks; |
1097 TUserModeCallback* listHead = aThread->iUserModeCallbacks; |
1093 do { |
1098 do { |
1094 if (TLinAddr(listHead) & 3) |
1099 if (TLinAddr(listHead) & 3) |