|
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32test\nkern\d_crazyints.cpp |
|
15 // |
|
16 // Overview: |
|
17 // kernel-side test (driver) for Crazy-Interrupts functionality |
|
18 // |
|
19 |
|
20 #include <platform.h> |
|
21 #include <nk_priv.h> |
|
22 #include <kernel/kern_priv.h> |
|
23 #include "d_crazyints.h" |
|
24 |
|
25 |
|
26 const TInt KMaxNumChannels = 1; // we only support one client at the time |
|
27 |
|
28 _LIT(KLddRootName,"d_crazyints"); |
|
29 _LIT(KIntTestThreadName,"InterruptsTest"); |
|
30 |
|
31 // Constructor |
|
32 DDeviceIntsTest::DDeviceIntsTest() |
|
33 { |
|
34 iParseMask = 0; |
|
35 iUnitsMask = 0; // No info, no PDD, no Units |
|
36 iVersion = TVersion(KIntTestMajorVersionNumber, |
|
37 KIntTestMinorVersionNumber, KIntTestBuildVersionNumber); |
|
38 } |
|
39 |
|
40 DDeviceIntsTest::~DDeviceIntsTest() |
|
41 { |
|
42 } |
|
43 |
|
44 // Install the device driver. |
|
45 TInt DDeviceIntsTest::Install() |
|
46 { |
|
47 return (SetName(&KLddRootName)); |
|
48 } |
|
49 |
|
50 void DDeviceIntsTest::GetCaps(TDes8& aDes) const |
|
51 { |
|
52 TPckgBuf<TCapsProxyClient> b; |
|
53 b().version = TVersion(KIntTestMajorVersionNumber, KIntTestMinorVersionNumber, KIntTestBuildVersionNumber); |
|
54 Kern::InfoCopy(aDes, b); |
|
55 } |
|
56 |
|
57 // Create a channel on the device. |
|
58 TInt DDeviceIntsTest::Create(DLogicalChannelBase*& aChannel) |
|
59 { |
|
60 if (iOpenChannels >= KMaxNumChannels) |
|
61 return KErrOverflow; |
|
62 |
|
63 aChannel = new DChannIntsTest; |
|
64 return aChannel ? KErrNone : KErrNoMemory; |
|
65 } |
|
66 |
|
67 DChannIntsTest::DChannIntsTest() |
|
68 #ifdef __SMP__ |
|
69 : iTimer(Handler, this) |
|
70 #endif |
|
71 { |
|
72 iClient = &Kern::CurrentThread(); |
|
73 // Increase the DThread's ref count so that it does not close without us |
|
74 ((DObject*)iClient)->Open(); |
|
75 } |
|
76 |
|
77 DChannIntsTest::~DChannIntsTest() |
|
78 { |
|
79 iDfcQue->Destroy(); |
|
80 // decrement the DThread's reference count |
|
81 Kern::SafeClose((DObject*&) iClient, NULL); |
|
82 } |
|
83 |
|
84 TInt DChannIntsTest::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) |
|
85 { |
|
86 TInt r = Kern::DynamicDfcQCreate(iDfcQue, KIntTestThreadPriority, KIntTestThreadName); |
|
87 |
|
88 if(r == KErrNone) |
|
89 { |
|
90 SetDfcQ(iDfcQue); |
|
91 iMsgQ.Receive(); |
|
92 } |
|
93 #ifdef __SMP__ |
|
94 return r; |
|
95 #else |
|
96 return KErrNotSupported; |
|
97 #endif |
|
98 } |
|
99 |
|
100 void DChannIntsTest::HandleMsg(TMessageBase* aMsg) |
|
101 { |
|
102 TThreadMessage& m = *(TThreadMessage*) aMsg; |
|
103 TInt id = m.iValue; |
|
104 |
|
105 if (id == ECloseMsg) |
|
106 { |
|
107 iMsgQ.iMessage->Complete(KErrNone, EFalse); |
|
108 return; |
|
109 } |
|
110 else if (id == KMaxTInt) |
|
111 { |
|
112 m.Complete(KErrNone, ETrue); |
|
113 return; |
|
114 } |
|
115 |
|
116 if (id < 0) |
|
117 { |
|
118 TRequestStatus* pS = (TRequestStatus*) m.Ptr0(); |
|
119 TInt r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2()); |
|
120 if (r != KErrNone) |
|
121 { |
|
122 Kern::RequestComplete(iClient, pS, r); |
|
123 } |
|
124 m.Complete(KErrNone, ETrue); |
|
125 } |
|
126 else |
|
127 { |
|
128 TInt r = DoControl(id, m.Ptr0(), m.Ptr1()); |
|
129 m.Complete(r, ETrue); |
|
130 } |
|
131 } |
|
132 |
|
133 #ifdef __SMP__ |
|
134 TBool DChannIntsTest::CrazyInterruptsEnabled() |
|
135 { |
|
136 // check, if crazy-interrupts are enabled.. |
|
137 TSuperPage& sp = Kern::SuperPage(); |
|
138 return (sp.KernelConfigFlags() & EKernelConfigSMPCrazyInterrupts); |
|
139 } |
|
140 |
|
141 // Isr handler - it will check, if previously was run on the same core.. |
|
142 void DChannIntsTest::Handler (TAny *aParam) |
|
143 { |
|
144 __KTRACE_OPT(KTESTFAST,Kern::Printf("Handler\n")); |
|
145 DChannIntsTest *a = (DChannIntsTest*) aParam; |
|
146 |
|
147 // clear the flag for the core that we're now executing.. |
|
148 TUint curr_core = NKern::CurrentCpu(); |
|
149 a->iStatus &= ~(1u << curr_core); |
|
150 |
|
151 // decrement the counter..and kick the timer again - as required.. |
|
152 TInt cnt = __e32_atomic_add_acq32(&a->iRunCount, ~(0u)); |
|
153 if(cnt >= 1) |
|
154 a->iTimer.Again(KTimerWaitValue); |
|
155 } |
|
156 |
|
157 // This test checks if the timer handler run in ISR context executes on all available |
|
158 // CPU cores when crazy interrupts are enabled. |
|
159 TInt DChannIntsTest::TestCrazyInts() |
|
160 { |
|
161 __KTRACE_OPT(KTESTFAST,Kern::Printf("TestCrazyInts")); |
|
162 |
|
163 if(!CrazyInterruptsEnabled()) |
|
164 return KErrNotSupported; |
|
165 |
|
166 // Check how many CPUs we have in the system -and set corresponding flags in |
|
167 // iStatus. As an indication, that ISRs are run on a different cores all these flags |
|
168 // should be cleared in the Handler. |
|
169 TUint status = 0; |
|
170 for(TInt i = 0; i < NKern::NumberOfCpus(); ++i) |
|
171 { |
|
172 status |= 1u << i; |
|
173 } |
|
174 iStatus = status; |
|
175 |
|
176 // Kick-off a Timer to run it's handler in a ISR context.. |
|
177 iRunCount = KNumOfTimes; |
|
178 iTimer.OneShot(KTimerWaitValue); |
|
179 |
|
180 //busy wait until it all completes.. |
|
181 while (__e32_atomic_load_acq32(&iRunCount) > 0) |
|
182 NKern::Sleep(1); |
|
183 |
|
184 if(iStatus) |
|
185 { |
|
186 if((iStatus ^ status) == 1) |
|
187 { |
|
188 // we must be running on the single core version, whilst the kernel flag is set |
|
189 // this might happen, if the Kernel (nkern) was not compiled with SMP_CRAZY_INTERRUPTS defined |
|
190 // check, if variant.mmh for this platform contains: macro SMP_CRAZY_INTERRUPTS |
|
191 Kern::Printf("Interrupts running only on CPU0 and EKernelConfigSMPCrazyInterrupts flag is set \n\r is this - wrong configuration? ", iStatus); |
|
192 } |
|
193 else |
|
194 Kern::Printf("ISR was not executed on all CPUs..(%x)", iStatus); |
|
195 |
|
196 return KErrGeneral; |
|
197 } |
|
198 |
|
199 return KErrNone; |
|
200 } |
|
201 #endif |
|
202 |
|
203 // to handle synchronous requests from the client |
|
204 TInt DChannIntsTest::DoControl(TInt aId, TAny* a1, TAny* a2) |
|
205 { |
|
206 TInt r = KErrNone; |
|
207 switch (aId) |
|
208 { |
|
209 case RBusIntTestClient::ETestCrazyInts: |
|
210 { |
|
211 #ifdef __SMP__ |
|
212 r = TestCrazyInts(); |
|
213 #else |
|
214 r = KErrNotSupported; |
|
215 #endif |
|
216 break; |
|
217 } |
|
218 |
|
219 default: |
|
220 { |
|
221 __KTRACE_OPT(KTESTFAST,Kern::Printf("DChannIntsTest::DoControl():Unrecognized value for aId=0x%x\n", aId)); |
|
222 r = KErrArgument; |
|
223 break; |
|
224 } |
|
225 } |
|
226 return r; |
|
227 } |
|
228 |
|
229 // to handle asynchronous requests from the client |
|
230 TInt DChannIntsTest::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2) |
|
231 { |
|
232 __KTRACE_OPT(KTESTFAST,Kern::Printf("DChannIntsTest::DoRequest(aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n", |
|
233 aId, aStatus, a1, a2)); |
|
234 |
|
235 TInt r = KErrNone; |
|
236 switch (aId) |
|
237 { |
|
238 default: |
|
239 { |
|
240 __KTRACE_OPT(KTESTFAST,Kern::Printf("DChannIntsTest::DoRequest(): unrecognized value for aId=0x%x\n", aId)); |
|
241 r = KErrArgument; |
|
242 break; |
|
243 } |
|
244 } |
|
245 return r; |
|
246 } |
|
247 |
|
248 // LDD entry point |
|
249 DECLARE_STANDARD_LDD() |
|
250 { |
|
251 return new DDeviceIntsTest; |
|
252 } |
|
253 |