|
1 /* |
|
2 * Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Implmentation of DMAv2 test code, common |
|
15 * to both user and kernel side |
|
16 * |
|
17 */ |
|
18 #ifdef __KERNEL_MODE__ |
|
19 #include <platform.h> |
|
20 |
|
21 #ifdef __DMASIM__ |
|
22 #ifdef __WINS__ |
|
23 typedef TLinAddr TPhysAddr; |
|
24 #endif |
|
25 static inline TPhysAddr LinToPhys(TLinAddr aLin) {return aLin;} |
|
26 #else |
|
27 static inline TPhysAddr LinToPhys(TLinAddr aLin) {return Epoc::LinearToPhysical(aLin);} |
|
28 #endif |
|
29 #endif |
|
30 |
|
31 #include "d_dma2.h" |
|
32 |
|
33 |
|
34 TInt Log2(TInt aNum) |
|
35 { |
|
36 TInt res = -1; |
|
37 while(aNum) |
|
38 { |
|
39 res++; |
|
40 aNum >>= 1; |
|
41 } |
|
42 return res; |
|
43 } |
|
44 |
|
45 TCallbackRecord::TCallbackRecord( |
|
46 TCbContext aContext, |
|
47 TInt aReq, |
|
48 TInt aReqSrc, |
|
49 TInt aReqDst, |
|
50 TInt aDes, |
|
51 TInt aDesSrc, |
|
52 TInt aDesDst, |
|
53 TInt aFrame, |
|
54 TInt aFrameSrc, |
|
55 TInt aFrameDst, |
|
56 TInt aPause, |
|
57 TInt aPauseSrc, |
|
58 TInt aPauseDst, |
|
59 TDmaResult aResult |
|
60 ) |
|
61 //Default iIsrRedoRequestResult is 1 as this is an invalid error code |
|
62 :iResult(aResult), iContext(aContext), iIsrRedoRequestResult(1) |
|
63 { |
|
64 SetCount(EDmaCallbackRequestCompletion, aReq); |
|
65 SetCount(EDmaCallbackRequestCompletion_Src, aReqSrc); |
|
66 SetCount(EDmaCallbackRequestCompletion_Dst, aReqDst); |
|
67 SetCount(EDmaCallbackDescriptorCompletion, aDes); |
|
68 SetCount(EDmaCallbackDescriptorCompletion_Src, aDesSrc); |
|
69 SetCount(EDmaCallbackDescriptorCompletion_Dst, aDesDst); |
|
70 SetCount(EDmaCallbackFrameCompletion, aFrame); |
|
71 SetCount(EDmaCallbackFrameCompletion_Src, aFrameSrc); |
|
72 SetCount(EDmaCallbackFrameCompletion_Dst, aFrameDst); |
|
73 SetCount(EDmaCallbackLinkedListPaused, aPause); |
|
74 SetCount(EDmaCallbackLinkedListPaused_Src, aPauseSrc); |
|
75 SetCount(EDmaCallbackLinkedListPaused_Dst, aPauseDst); |
|
76 } |
|
77 |
|
78 TCallbackRecord TCallbackRecord::Empty() |
|
79 { |
|
80 return TCallbackRecord(EInvalid,0,0,0,0,0,0,0,0,0,0,0,0,EDmaResultError); |
|
81 } |
|
82 |
|
83 void TCallbackRecord::Reset() |
|
84 { |
|
85 new (this) TCallbackRecord(); |
|
86 } |
|
87 |
|
88 TBool TCallbackRecord::operator == (const TCallbackRecord aOther) const |
|
89 { |
|
90 return (memcompare((TUint8*)this, sizeof(*this), (TUint8*)&aOther, sizeof(aOther)) == 0); |
|
91 } |
|
92 |
|
93 TInt TCallbackRecord::GetCount(TDmaCallbackType aCbType) const |
|
94 { |
|
95 const TInt index = BitToIndex(aCbType); |
|
96 return iCallbackLog[index]; |
|
97 } |
|
98 |
|
99 void TCallbackRecord::SetCount(TDmaCallbackType aCbType, TInt aCount) |
|
100 { |
|
101 const TInt index = BitToIndex(aCbType); |
|
102 iCallbackLog[index] = aCount; |
|
103 } |
|
104 |
|
105 TInt TCallbackRecord::BitToIndex(TDmaCallbackType aCbType) const |
|
106 { |
|
107 const TInt index = Log2(aCbType); |
|
108 TEST_ASSERT(index >=0 && index < KNumberOfCallbacks); |
|
109 |
|
110 return index; |
|
111 } |
|
112 |
|
113 void TCallbackRecord::ProcessCallback(TUint aCallbackMask, TDmaResult aResult) |
|
114 { |
|
115 // This function may be called several |
|
116 // times and will accumulate the number of each callback |
|
117 // received. However, it will only ever remember the last |
|
118 // result and context value, |
|
119 iResult = aResult; |
|
120 iContext = CurrentContext(); |
|
121 TEST_ASSERT(iContext != EInvalid); |
|
122 |
|
123 for(TInt i=0; i < KNumberOfCallbacks; i++) |
|
124 { |
|
125 if(aCallbackMask & 1) |
|
126 { |
|
127 iCallbackLog[i]++; |
|
128 } |
|
129 aCallbackMask >>= 1; |
|
130 } |
|
131 // Assert that we have handled all bits |
|
132 // if not then maybe KNumberOfCallbacks is too small |
|
133 // or there is a spurious bit in aCallbackMask |
|
134 TEST_ASSERT(aCallbackMask == 0); |
|
135 } |
|
136 |
|
137 TCallbackRecord::TCbContext TCallbackRecord::CurrentContext() const |
|
138 { |
|
139 #ifdef __KERNEL_MODE__ |
|
140 switch(NKern::CurrentContext()) |
|
141 { |
|
142 case NKern::EThread: |
|
143 return EThread; |
|
144 case NKern::EInterrupt: |
|
145 return EIsr; |
|
146 //Fall-through: If context is IDFC or the EEscaped marker occur |
|
147 //it is an error |
|
148 case NKern::EIDFC: |
|
149 case NKern::EEscaped: |
|
150 default: |
|
151 return EInvalid; |
|
152 } |
|
153 #else |
|
154 //for the benefit of user-mode testing |
|
155 return EThread; |
|
156 #endif |
|
157 } |
|
158 |
|
159 void TCallbackRecord::Print() const |
|
160 { |
|
161 PRINT(GetCount(EDmaCallbackRequestCompletion)); |
|
162 PRINT(GetCount(EDmaCallbackRequestCompletion_Src)); |
|
163 PRINT(GetCount(EDmaCallbackRequestCompletion_Dst)); |
|
164 PRINT(GetCount(EDmaCallbackDescriptorCompletion)); |
|
165 PRINT(GetCount(EDmaCallbackDescriptorCompletion_Src)); |
|
166 PRINT(GetCount(EDmaCallbackDescriptorCompletion_Dst)); |
|
167 PRINT(GetCount(EDmaCallbackFrameCompletion)); |
|
168 PRINT(GetCount(EDmaCallbackFrameCompletion_Src)); |
|
169 PRINT(GetCount(EDmaCallbackFrameCompletion_Dst)); |
|
170 PRINT(GetCount(EDmaCallbackLinkedListPaused)); |
|
171 PRINT(GetCount(EDmaCallbackLinkedListPaused_Src)); |
|
172 PRINT(GetCount(EDmaCallbackLinkedListPaused_Dst)); |
|
173 PRINT(iResult); |
|
174 PRINT(iContext); |
|
175 PRINT(iIsrRedoRequestResult); |
|
176 } |
|
177 |
|
178 TDmacTestCaps::TDmacTestCaps() |
|
179 :iPILVersion(1) |
|
180 { |
|
181 } |
|
182 |
|
183 TDmacTestCaps::TDmacTestCaps(const SDmacCaps& aDmacCaps, TInt aVersion) |
|
184 :SDmacCaps(aDmacCaps), iPILVersion(aVersion) |
|
185 {} |
|
186 |
|
187 TAddrRange::TAddrRange(TUint aStart, TUint aLength) |
|
188 :iStart(aStart), iLength(aLength) |
|
189 { |
|
190 } |
|
191 |
|
192 TBool TAddrRange::Contains(TAddrRange aRange) const |
|
193 { |
|
194 return Contains(aRange.Start()) && Contains(aRange.End()); |
|
195 } |
|
196 |
|
197 TBool TAddrRange::Overlaps(const TAddrRange& aRange) const |
|
198 { |
|
199 return (aRange.Contains(iStart) || aRange.Contains(End()) || |
|
200 Contains(aRange.Start()) || Contains(aRange.End())); |
|
201 } |
|
202 |
|
203 TBool TAddrRange::IsFilled(TUint8 aValue) const |
|
204 { |
|
205 TUint8* buffer = reinterpret_cast<TUint8*>(iStart); |
|
206 for(TUint i = 0; i < iLength; i++) |
|
207 { |
|
208 if(buffer[i] != aValue) |
|
209 return EFalse; |
|
210 } |
|
211 return ETrue; |
|
212 } |
|
213 |
|
214 /** |
|
215 If addresses have been left as KPhysAddrInvalid or the count as 0 (ie. the |
|
216 default values used for IsrRedoRequest) then substitute the values from |
|
217 aTransferArgs. |
|
218 */ |
|
219 void TAddressParms::Substitute(const TDmaTransferArgs& aTransferArgs) |
|
220 { |
|
221 Substitute(GetAddrParms(aTransferArgs)); |
|
222 } |
|
223 |
|
224 /** |
|
225 If addresses have been left as KPhysAddrInvalid or the count as 0 (ie. the |
|
226 default values used for IsrRedoRequest) then substitute the values from |
|
227 aTransferArgs. |
|
228 */ |
|
229 void TAddressParms::Substitute(const TAddressParms& aAddrParams) |
|
230 { |
|
231 if(iSrcAddr == KPhysAddrInvalidUser) |
|
232 iSrcAddr = aAddrParams.iSrcAddr; |
|
233 |
|
234 if(iDstAddr == KPhysAddrInvalidUser) |
|
235 iDstAddr = aAddrParams.iDstAddr; |
|
236 |
|
237 if(iTransferCount == 0) |
|
238 iTransferCount = aAddrParams.iTransferCount; |
|
239 } |
|
240 |
|
241 /** |
|
242 Addresses are converted into absolute, |
|
243 addresses (virtual in user mode, physical in kernel) |
|
244 unless they are KPhysAddrInvalid |
|
245 */ |
|
246 void TAddressParms::Fixup(TLinAddr aChunkBase) |
|
247 { |
|
248 if(iSrcAddr != KPhysAddrInvalidUser) |
|
249 { |
|
250 iSrcAddr += aChunkBase; |
|
251 |
|
252 #ifdef __KERNEL_MODE__ |
|
253 iSrcAddr = LinToPhys(iSrcAddr); |
|
254 TEST_ASSERT(iSrcAddr != KPhysAddrInvalid); |
|
255 #endif |
|
256 } |
|
257 #ifndef __KERNEL_MODE__ |
|
258 else |
|
259 { |
|
260 // Substitute must be called before |
|
261 // Fixup on user side |
|
262 TEST_FAULT; |
|
263 } |
|
264 #endif |
|
265 |
|
266 if(iDstAddr != KPhysAddrInvalidUser) |
|
267 { |
|
268 iDstAddr += aChunkBase; |
|
269 |
|
270 #ifdef __KERNEL_MODE__ |
|
271 iDstAddr = LinToPhys(iDstAddr); |
|
272 TEST_ASSERT(iDstAddr != KPhysAddrInvalid); |
|
273 #endif |
|
274 } |
|
275 #ifndef __KERNEL_MODE__ |
|
276 else |
|
277 { |
|
278 // Substitute must be called before |
|
279 // Fixup on user side |
|
280 TEST_FAULT; |
|
281 } |
|
282 #endif |
|
283 } |
|
284 |
|
285 TBool TAddressParms::CheckRange(TLinAddr aStart, TUint aSize) |
|
286 { |
|
287 TAddrRange chunk(aStart, aSize); |
|
288 return chunk.Contains(SourceRange()) && chunk.Contains(DestRange()); |
|
289 } |
|
290 |
|
291 /** |
|
292 @return ETrue if the source or destination range of this object |
|
293 overlaps with aRange |
|
294 */ |
|
295 TBool TAddressParms::Overlaps(const TAddrRange aRange) const |
|
296 { |
|
297 return SourceRange().Overlaps(aRange) || DestRange().Overlaps(aRange); |
|
298 } |
|
299 |
|
300 /** |
|
301 @return ETrue if either the source or dest range of this |
|
302 overlap with either of those of aParm |
|
303 */ |
|
304 TBool TAddressParms::Overlaps(const TAddressParms aParm) const |
|
305 { |
|
306 return Overlaps(aParm.SourceRange()) || Overlaps(aParm.DestRange()); |
|
307 } |
|
308 |
|
309 TBool TAddressParms::operator==(const TAddressParms& aOther) const |
|
310 { |
|
311 return iSrcAddr == aOther.iSrcAddr && |
|
312 iDstAddr == aOther.iDstAddr && |
|
313 iTransferCount == aOther.iTransferCount; |
|
314 } |
|
315 |
|
316 TAddressParms GetAddrParms(const TDmaTransferArgs& aArgs) |
|
317 { |
|
318 return TAddressParms(aArgs); |
|
319 } |
|
320 |
|
321 TAddrRange TAddressParms::SourceRange() const |
|
322 { |
|
323 return TAddrRange(iSrcAddr, iTransferCount); |
|
324 } |
|
325 |
|
326 TAddrRange TAddressParms::DestRange() const |
|
327 { |
|
328 return TAddrRange(iDstAddr, iTransferCount); |
|
329 } |
|
330 |
|
331 void TAddressParms::MakePhysical() |
|
332 { |
|
333 #ifdef __KERNEL_MODE__ |
|
334 iSrcAddr = LinToPhys(iSrcAddr); |
|
335 TEST_ASSERT(iSrcAddr != KPhysAddrInvalid); |
|
336 iDstAddr = LinToPhys(iDstAddr); |
|
337 TEST_ASSERT(iDstAddr != KPhysAddrInvalid); |
|
338 #else |
|
339 TEST_FAULT; |
|
340 #endif |
|
341 } |
|
342 |
|
343 void SetAddrParms(TDmaTransferArgs& aTransferArgs, const TAddressParms& aAddrParams) |
|
344 { |
|
345 aTransferArgs.iSrcConfig.iAddr = aAddrParams.iSrcAddr; |
|
346 aTransferArgs.iDstConfig.iAddr = aAddrParams.iDstAddr; |
|
347 aTransferArgs.iTransferCount = aAddrParams.iTransferCount; |
|
348 } |
|
349 |
|
350 TIsrRequeArgs TIsrRequeArgsSet::GetArgs() |
|
351 { |
|
352 TEST_ASSERT(!IsEmpty()); |
|
353 const TIsrRequeArgs args(iRequeArgs[iIndex]); |
|
354 iIndex++; |
|
355 iCount--; |
|
356 return args; |
|
357 } |
|
358 |
|
359 void TIsrRequeArgsSet::Substitute(const TDmaTransferArgs& aTransferArgs) |
|
360 { |
|
361 TAddressParms initial(aTransferArgs); |
|
362 |
|
363 //if on user side it is assumed that aTransferArgs addresses will be offset |
|
364 //based (from a virtual address). In kernel mode it is expected that address |
|
365 //will be absolute virtual addresses, and must therefore be made physical |
|
366 #ifdef __KERNEL_MODE__ |
|
367 initial.MakePhysical(); |
|
368 #endif |
|
369 |
|
370 const TAddressParms* previous = &initial; |
|
371 |
|
372 for(TInt i=0; i<iCount; i++) |
|
373 { |
|
374 TAddressParms& current = iRequeArgs[i]; |
|
375 current.Substitute(*previous); |
|
376 previous = ¤t; |
|
377 } |
|
378 } |
|
379 |
|
380 void TIsrRequeArgsSet::Fixup(TLinAddr aChunkBase) |
|
381 { |
|
382 for(TInt i=0; i<iCount; i++) |
|
383 { |
|
384 iRequeArgs[i].Fixup(aChunkBase); |
|
385 } |
|
386 } |
|
387 |
|
388 /** Check that both source and destination of ISR reque args will lie within the |
|
389 range specified by aStart and aSize. |
|
390 |
|
391 @param aStart The linear base address of the region |
|
392 @param aSize The size of the region |
|
393 */ |
|
394 TBool TIsrRequeArgs::CheckRange(TLinAddr aStart, TUint aSize) const |
|
395 { |
|
396 TUint chunkStart = 0; |
|
397 #ifdef __KERNEL_MODE__ |
|
398 chunkStart = LinToPhys(aStart); |
|
399 TEST_ASSERT(chunkStart != KPhysAddrInvalid); |
|
400 #else |
|
401 chunkStart = aStart; |
|
402 #endif |
|
403 |
|
404 // If an address is still KPhysAddrInvalid it means the arguments haven't |
|
405 // yet been substituted |
|
406 TAddrRange chunk(chunkStart, aSize); |
|
407 TBool sourceOk = (iSrcAddr != KPhysAddrInvalid) && chunk.Contains(SourceRange()); |
|
408 |
|
409 TBool destOk = (iDstAddr != KPhysAddrInvalid) && chunk.Contains(DestRange()); |
|
410 |
|
411 TBool ok = sourceOk && destOk; |
|
412 if(!ok) |
|
413 { |
|
414 PRINTF(("Error, re-queue args: ")); |
|
415 TBuf<128> buf; |
|
416 AppendString(buf); |
|
417 PRINTF(("%S", &buf)); |
|
418 PRINTF(("overflow buffer base=0x%08x, size=0x%08x", chunkStart, aSize)); |
|
419 } |
|
420 return ok; |
|
421 } |
|
422 |
|
423 TBool TIsrRequeArgsSet::CheckRange(TLinAddr aAddr, TUint aSize) const |
|
424 { |
|
425 for(TInt i=0; i<iCount; i++) |
|
426 { |
|
427 if(!iRequeArgs[i].CheckRange(aAddr, aSize)) |
|
428 return EFalse; |
|
429 } |
|
430 return ETrue; |
|
431 } |
|
432 |
|
433 TBool TIsrRequeArgsSet::CheckRange(TLinAddr aAddr, TUint aSize, const TDmaTransferArgs& aInitialParms) const |
|
434 { |
|
435 // apply substitution, without modifying the original |
|
436 TIsrRequeArgsSet copy(*this); |
|
437 copy.Substitute(aInitialParms); |
|
438 |
|
439 return copy.CheckRange(aAddr, aSize); |
|
440 } |
|
441 |